diff mbox

[v2,1/2] qxl: introduce QXLCookie

Message ID 1329468300-6507-1-git-send-email-alevy@redhat.com
State New
Headers show

Commit Message

Alon Levy Feb. 17, 2012, 8:44 a.m. UTC
Will be used in the next patch.

Signed-off-by: Alon Levy <alevy@redhat.com>
---
 hw/qxl-render.c    |    2 +-
 hw/qxl.c           |   60 +++++++++++++++++++++++++++++++++++++--------------
 hw/qxl.h           |    2 +-
 ui/spice-display.c |   26 ++++++++++++++++++++--
 ui/spice-display.h |   12 ++++++++++
 5 files changed, 80 insertions(+), 22 deletions(-)

Comments

Marc-André Lureau Feb. 17, 2012, 12:49 p.m. UTC | #1
Hi

On Fri, Feb 17, 2012 at 9:44 AM, Alon Levy <alevy@redhat.com> wrote:
> +/* called from spice server thread context only */
> +static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token)
> +{
> +    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
> +    QXLCookie *cookie = (QXLCookie*)cookie_token;
> +
> +    switch (cookie->type) {

We still have spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, 0);

So cookie might be NULL in this case.
Marc-André Lureau Feb. 17, 2012, 12:54 p.m. UTC | #2
Hi

On Fri, Feb 17, 2012 at 9:44 AM, Alon Levy <alevy@redhat.com> wrote:
> +QXLCookie *qxl_cookie_new(int type, uint64_t io, uint64_t data)
> +{
> +    QXLCookie *cookie;
> +
> +    cookie = g_malloc0(sizeof(*cookie));
> +    cookie->type = type;
> +    cookie->io = io;
> +    cookie->data = data;
> +    return cookie;
> +}

I don't know if it's prohibited in qemu code, but g_slice would be a
good fit here: frequently allocated bits of same size.
Gerd Hoffmann Feb. 17, 2012, 1:11 p.m. UTC | #3
On 02/17/12 09:44, Alon Levy wrote:
> Will be used in the next patch.
> 
> Signed-off-by: Alon Levy <alevy@redhat.com>
> ---
>  hw/qxl-render.c    |    2 +-
>  hw/qxl.c           |   60 +++++++++++++++++++++++++++++++++++++--------------
>  hw/qxl.h           |    2 +-
>  ui/spice-display.c |   26 ++++++++++++++++++++--
>  ui/spice-display.h |   12 ++++++++++
>  5 files changed, 80 insertions(+), 22 deletions(-)
> 
> diff --git a/hw/qxl-render.c b/hw/qxl-render.c
> index 133d093..b238b96 100644
> --- a/hw/qxl-render.c
> +++ b/hw/qxl-render.c
> @@ -133,7 +133,7 @@ void qxl_render_update(PCIQXLDevice *qxl)
>  
>      memset(dirty, 0, sizeof(dirty));
>      qxl_spice_update_area(qxl, 0, &update,
> -                          dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC);
> +                          dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC, NULL);
>      if (redraw) {
>          memset(dirty, 0, sizeof(dirty));
>          dirty[0] = update;
> diff --git a/hw/qxl.c b/hw/qxl.c
> index ac69125..02708e3 100644
> --- a/hw/qxl.c
> +++ b/hw/qxl.c
> @@ -143,15 +143,20 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
>                             struct QXLRect *area, struct QXLRect *dirty_rects,
>                             uint32_t num_dirty_rects,
>                             uint32_t clear_dirty_region,
> -                           qxl_async_io async)
> +                           qxl_async_io async, QXLCookie *cookie)
>  {
>      if (async == QXL_SYNC) {
>          qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area,
>                          dirty_rects, num_dirty_rects, clear_dirty_region);
>      } else {
>  #if SPICE_INTERFACE_QXL_MINOR >= 1
> +        if (cookie == NULL) {
> +            cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
> +                                    QXL_IO_UPDATE_AREA_ASYNC,
> +                                    0);
> +        }

Hmm, why that?  If the callers want a cookie, then they should
explicitly pass in what they want instead of expecting the function to
magically do the correct thing.  If the callers don't need a cookie,
then use something like QXL_COOKIE_TYPE_UNUSED or simply pass on the
NULL pointer.

cheers,
  Gerd
Alon Levy Feb. 17, 2012, 1:20 p.m. UTC | #4
On Fri, Feb 17, 2012 at 10:44:59AM +0200, Alon Levy wrote:
> Will be used in the next patch.

NACK these two, Marc Andre found a cookie I missed, and the bz in the
commit message is a dup of an existing bug (747011).

> 
> Signed-off-by: Alon Levy <alevy@redhat.com>
> ---
>  hw/qxl-render.c    |    2 +-
>  hw/qxl.c           |   60 +++++++++++++++++++++++++++++++++++++--------------
>  hw/qxl.h           |    2 +-
>  ui/spice-display.c |   26 ++++++++++++++++++++--
>  ui/spice-display.h |   12 ++++++++++
>  5 files changed, 80 insertions(+), 22 deletions(-)
> 
> diff --git a/hw/qxl-render.c b/hw/qxl-render.c
> index 133d093..b238b96 100644
> --- a/hw/qxl-render.c
> +++ b/hw/qxl-render.c
> @@ -133,7 +133,7 @@ void qxl_render_update(PCIQXLDevice *qxl)
>  
>      memset(dirty, 0, sizeof(dirty));
>      qxl_spice_update_area(qxl, 0, &update,
> -                          dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC);
> +                          dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC, NULL);
>      if (redraw) {
>          memset(dirty, 0, sizeof(dirty));
>          dirty[0] = update;
> diff --git a/hw/qxl.c b/hw/qxl.c
> index ac69125..02708e3 100644
> --- a/hw/qxl.c
> +++ b/hw/qxl.c
> @@ -143,15 +143,20 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
>                             struct QXLRect *area, struct QXLRect *dirty_rects,
>                             uint32_t num_dirty_rects,
>                             uint32_t clear_dirty_region,
> -                           qxl_async_io async)
> +                           qxl_async_io async, QXLCookie *cookie)
>  {
>      if (async == QXL_SYNC) {
>          qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area,
>                          dirty_rects, num_dirty_rects, clear_dirty_region);
>      } else {
>  #if SPICE_INTERFACE_QXL_MINOR >= 1
> +        if (cookie == NULL) {
> +            cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
> +                                    QXL_IO_UPDATE_AREA_ASYNC,
> +                                    0);
> +        }
>          spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area,
> -                                    clear_dirty_region, 0);
> +                                    clear_dirty_region, (uint64_t)cookie);
>  #else
>          abort();
>  #endif
> @@ -171,11 +176,13 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id,
>                                             qxl_async_io async)
>  {
>      if (async) {
> -#if SPICE_INTERFACE_QXL_MINOR < 1
> -        abort();
> -#else
> +#if SPICE_INTERFACE_QXL_MINOR >= 1
>          spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id,
> -                                        (uint64_t)id);
> +                (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
> +                                         QXL_IO_DESTROY_SURFACE_ASYNC,
> +                                         id));
> +#else
> +        abort();
>  #endif
>      } else {
>          qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
> @@ -217,10 +224,13 @@ static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl)
>  static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
>  {
>      if (async) {
> -#if SPICE_INTERFACE_QXL_MINOR < 1
> -        abort();
> +#if SPICE_INTERFACE_QXL_MINOR >= 1
> +        spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl,
> +                (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
> +                                         QXL_IO_DESTROY_ALL_SURFACES,
> +                                         0));
>  #else
> -        spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, 0);
> +        abort();
>  #endif
>      } else {
>          qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
> @@ -737,18 +747,20 @@ static void qxl_create_guest_primary_complete(PCIQXLDevice *d);
>  
>  #if SPICE_INTERFACE_QXL_MINOR >= 1
>  
> -/* called from spice server thread context only */
> -static void interface_async_complete(QXLInstance *sin, uint64_t cookie)
> +static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie)
>  {
> -    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
>      uint32_t current_async;
>  
>      qemu_mutex_lock(&qxl->async_lock);
>      current_async = qxl->current_async;
>      qxl->current_async = QXL_UNDEFINED_IO;
>      qemu_mutex_unlock(&qxl->async_lock);
> +    dprint(qxl, 2, "async_complete: %d (%p) done\n", current_async, cookie);
> +    if (current_async != cookie->io) {
> +        fprintf(stderr, "qxl: %s: error: current_async = %d != %ld = cookie->io\n",
> +                __func__, current_async, cookie->io);
> +    }
>  
> -    dprint(qxl, 2, "async_complete: %d (%ld) done\n", current_async, cookie);
>      switch (current_async) {
>      case QXL_IO_CREATE_PRIMARY_ASYNC:
>          qxl_create_guest_primary_complete(qxl);
> @@ -757,12 +769,28 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie)
>          qxl_spice_destroy_surfaces_complete(qxl);
>          break;
>      case QXL_IO_DESTROY_SURFACE_ASYNC:
> -        qxl_spice_destroy_surface_wait_complete(qxl, (uint32_t)cookie);
> +        qxl_spice_destroy_surface_wait_complete(qxl, (uint32_t)cookie->data);
>          break;
>      }
>      qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD);
>  }
>  
> +/* called from spice server thread context only */
> +static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token)
> +{
> +    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
> +    QXLCookie *cookie = (QXLCookie*)cookie_token;
> +
> +    switch (cookie->type) {
> +    case QXL_COOKIE_TYPE_IO:
> +        interface_async_complete_io(qxl, cookie);
> +        break;
> +    default:
> +        fprintf(stderr, "qxl: %s: unexpected cookie type %d\n", __func__, cookie->type);
> +    }
> +    g_free(cookie);
> +}
> +
>  #endif
>  
>  static const QXLInterface qxl_interface = {
> @@ -1077,9 +1105,7 @@ static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async)
>      if (d->mode == QXL_MODE_UNDEFINED) {
>          return 0;
>      }
> -
>      dprint(d, 1, "%s\n", __FUNCTION__);
> -
>      d->mode = QXL_MODE_UNDEFINED;
>      qemu_spice_destroy_primary_surface(&d->ssd, 0, async);
>      qxl_spice_reset_cursor(d);
> @@ -1215,7 +1241,7 @@ async_common:
>      {
>          QXLRect update = d->ram->update_area;
>          qxl_spice_update_area(d, d->ram->update_surface,
> -                              &update, NULL, 0, 0, async);
> +                              &update, NULL, 0, 0, async, NULL);
>          break;
>      }
>      case QXL_IO_NOTIFY_CMD:
> diff --git a/hw/qxl.h b/hw/qxl.h
> index 766aa6d..666dd78 100644
> --- a/hw/qxl.h
> +++ b/hw/qxl.h
> @@ -118,7 +118,7 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
>                             struct QXLRect *area, struct QXLRect *dirty_rects,
>                             uint32_t num_dirty_rects,
>                             uint32_t clear_dirty_region,
> -                           qxl_async_io async);
> +                           qxl_async_io async, QXLCookie *cookie);
>  void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
>                                 uint32_t count);
>  void qxl_spice_oom(PCIQXLDevice *qxl);
> diff --git a/ui/spice-display.c b/ui/spice-display.c
> index 6c302a3..680e6f4 100644
> --- a/ui/spice-display.c
> +++ b/ui/spice-display.c
> @@ -60,12 +60,26 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
>      dest->right = MAX(dest->right, r->right);
>  }
>  
> +QXLCookie *qxl_cookie_new(int type, uint64_t io, uint64_t data)
> +{
> +    QXLCookie *cookie;
> +
> +    cookie = g_malloc0(sizeof(*cookie));
> +    cookie->type = type;
> +    cookie->io = io;
> +    cookie->data = data;
> +    return cookie;
> +}
> +
>  void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot,
>                              qxl_async_io async)
>  {
>      if (async != QXL_SYNC) {
>  #if SPICE_INTERFACE_QXL_MINOR >= 1
> -        spice_qxl_add_memslot_async(&ssd->qxl, memslot, 0);
> +        spice_qxl_add_memslot_async(&ssd->qxl, memslot,
> +                (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
> +                                         QXL_IO_MEMSLOT_ADD_ASYNC,
> +                                         0));
>  #else
>          abort();
>  #endif
> @@ -85,7 +99,10 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
>  {
>      if (async != QXL_SYNC) {
>  #if SPICE_INTERFACE_QXL_MINOR >= 1
> -        spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, 0);
> +        spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface,
> +                (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
> +                                         QXL_IO_CREATE_PRIMARY_ASYNC,
> +                                         0));
>  #else
>          abort();
>  #endif
> @@ -100,7 +117,10 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd,
>  {
>      if (async != QXL_SYNC) {
>  #if SPICE_INTERFACE_QXL_MINOR >= 1
> -        spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, 0);
> +        spice_qxl_destroy_primary_surface_async(&ssd->qxl, id,
> +                (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
> +                                         QXL_IO_DESTROY_PRIMARY_ASYNC,
> +                                         0));
>  #else
>          abort();
>  #endif
> diff --git a/ui/spice-display.h b/ui/spice-display.h
> index 5e52df9..c8747ab 100644
> --- a/ui/spice-display.h
> +++ b/ui/spice-display.h
> @@ -48,6 +48,18 @@ typedef enum qxl_async_io {
>      QXL_ASYNC,
>  } qxl_async_io;
>  
> +enum {
> +    QXL_COOKIE_TYPE_IO,
> +};
> +
> +typedef struct QXLCookie {
> +    int      type;
> +    uint64_t io;
> +    uint64_t data;
> +} QXLCookie;
> +
> +QXLCookie *qxl_cookie_new(int type, uint64_t io, uint64_t data);
> +
>  typedef struct SimpleSpiceDisplay SimpleSpiceDisplay;
>  typedef struct SimpleSpiceUpdate SimpleSpiceUpdate;
>  
> -- 
> 1.7.9
> 
>
Alon Levy Feb. 17, 2012, 3:16 p.m. UTC | #5
On Fri, Feb 17, 2012 at 02:11:40PM +0100, Gerd Hoffmann wrote:
> On 02/17/12 09:44, Alon Levy wrote:
> > Will be used in the next patch.
> > 
> > Signed-off-by: Alon Levy <alevy@redhat.com>
> > ---
> >  hw/qxl-render.c    |    2 +-
> >  hw/qxl.c           |   60 +++++++++++++++++++++++++++++++++++++--------------
> >  hw/qxl.h           |    2 +-
> >  ui/spice-display.c |   26 ++++++++++++++++++++--
> >  ui/spice-display.h |   12 ++++++++++
> >  5 files changed, 80 insertions(+), 22 deletions(-)
> > 
> > diff --git a/hw/qxl-render.c b/hw/qxl-render.c
> > index 133d093..b238b96 100644
> > --- a/hw/qxl-render.c
> > +++ b/hw/qxl-render.c
> > @@ -133,7 +133,7 @@ void qxl_render_update(PCIQXLDevice *qxl)
> >  
> >      memset(dirty, 0, sizeof(dirty));
> >      qxl_spice_update_area(qxl, 0, &update,
> > -                          dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC);
> > +                          dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC, NULL);
> >      if (redraw) {
> >          memset(dirty, 0, sizeof(dirty));
> >          dirty[0] = update;
> > diff --git a/hw/qxl.c b/hw/qxl.c
> > index ac69125..02708e3 100644
> > --- a/hw/qxl.c
> > +++ b/hw/qxl.c
> > @@ -143,15 +143,20 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
> >                             struct QXLRect *area, struct QXLRect *dirty_rects,
> >                             uint32_t num_dirty_rects,
> >                             uint32_t clear_dirty_region,
> > -                           qxl_async_io async)
> > +                           qxl_async_io async, QXLCookie *cookie)
> >  {
> >      if (async == QXL_SYNC) {
> >          qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area,
> >                          dirty_rects, num_dirty_rects, clear_dirty_region);
> >      } else {
> >  #if SPICE_INTERFACE_QXL_MINOR >= 1
> > +        if (cookie == NULL) {
> > +            cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
> > +                                    QXL_IO_UPDATE_AREA_ASYNC,
> > +                                    0);
> > +        }
> 
> Hmm, why that?  If the callers want a cookie, then they should
> explicitly pass in what they want instead of expecting the function to
> magically do the correct thing.  If the callers don't need a cookie,
> then use something like QXL_COOKIE_TYPE_UNUSED or simply pass on the
> NULL pointer.

I can move it to the users if it makes it a little less magic.

Note that I will be sending a revized version, since:
1) I forgot about my previous attempt (october 2010,
http://lists.gnu.org/archive/html/qemu-devel/2011-10/msg02758.html)
2) there are a few bugs with this approach, that I fixed correctly back
then: one is the async monitor command, which I will not send this time
since I don't want to get into the same argument.
3) the second is the dirty rectangles, for which I have to raise
SPICE_INTERFACE_QXL_MINOR.

> 
> cheers,
>   Gerd
>
Alon Levy Feb. 17, 2012, 7:09 p.m. UTC | #6
On Fri, Feb 17, 2012 at 01:49:20PM +0100, Marc-André Lureau wrote:
> Hi
> 
> On Fri, Feb 17, 2012 at 9:44 AM, Alon Levy <alevy@redhat.com> wrote:
> > +/* called from spice server thread context only */
> > +static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token)
> > +{
> > +    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
> > +    QXLCookie *cookie = (QXLCookie*)cookie_token;
> > +
> > +    switch (cookie->type) {
> 
> We still have spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, 0);
> 
> So cookie might be NULL in this case.

Yeah, Marc Andre also noticed (exprimentally - you take the cake on the
review :).

> 
> -- 
> Marc-André Lureau
Alon Levy Feb. 17, 2012, 7:21 p.m. UTC | #7
On Fri, Feb 17, 2012 at 09:09:11PM +0200, Alon Levy wrote:
> On Fri, Feb 17, 2012 at 01:49:20PM +0100, Marc-André Lureau wrote:
> > Hi
> > 
> > On Fri, Feb 17, 2012 at 9:44 AM, Alon Levy <alevy@redhat.com> wrote:
> > > +/* called from spice server thread context only */
> > > +static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token)
> > > +{
> > > +    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
> > > +    QXLCookie *cookie = (QXLCookie*)cookie_token;
> > > +
> > > +    switch (cookie->type) {
> > 
> > We still have spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, 0);
> > 
> > So cookie might be NULL in this case.
> 
> Yeah, Marc Andre also noticed (exprimentally - you take the cake on the
> review :).

Please ignore.

> 
> > 
> > -- 
> > Marc-André Lureau
>
diff mbox

Patch

diff --git a/hw/qxl-render.c b/hw/qxl-render.c
index 133d093..b238b96 100644
--- a/hw/qxl-render.c
+++ b/hw/qxl-render.c
@@ -133,7 +133,7 @@  void qxl_render_update(PCIQXLDevice *qxl)
 
     memset(dirty, 0, sizeof(dirty));
     qxl_spice_update_area(qxl, 0, &update,
-                          dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC);
+                          dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC, NULL);
     if (redraw) {
         memset(dirty, 0, sizeof(dirty));
         dirty[0] = update;
diff --git a/hw/qxl.c b/hw/qxl.c
index ac69125..02708e3 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -143,15 +143,20 @@  void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
                            struct QXLRect *area, struct QXLRect *dirty_rects,
                            uint32_t num_dirty_rects,
                            uint32_t clear_dirty_region,
-                           qxl_async_io async)
+                           qxl_async_io async, QXLCookie *cookie)
 {
     if (async == QXL_SYNC) {
         qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area,
                         dirty_rects, num_dirty_rects, clear_dirty_region);
     } else {
 #if SPICE_INTERFACE_QXL_MINOR >= 1
+        if (cookie == NULL) {
+            cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                    QXL_IO_UPDATE_AREA_ASYNC,
+                                    0);
+        }
         spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area,
-                                    clear_dirty_region, 0);
+                                    clear_dirty_region, (uint64_t)cookie);
 #else
         abort();
 #endif
@@ -171,11 +176,13 @@  static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id,
                                            qxl_async_io async)
 {
     if (async) {
-#if SPICE_INTERFACE_QXL_MINOR < 1
-        abort();
-#else
+#if SPICE_INTERFACE_QXL_MINOR >= 1
         spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id,
-                                        (uint64_t)id);
+                (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                         QXL_IO_DESTROY_SURFACE_ASYNC,
+                                         id));
+#else
+        abort();
 #endif
     } else {
         qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
@@ -217,10 +224,13 @@  static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl)
 static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
 {
     if (async) {
-#if SPICE_INTERFACE_QXL_MINOR < 1
-        abort();
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+        spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl,
+                (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                         QXL_IO_DESTROY_ALL_SURFACES,
+                                         0));
 #else
-        spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, 0);
+        abort();
 #endif
     } else {
         qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
@@ -737,18 +747,20 @@  static void qxl_create_guest_primary_complete(PCIQXLDevice *d);
 
 #if SPICE_INTERFACE_QXL_MINOR >= 1
 
-/* called from spice server thread context only */
-static void interface_async_complete(QXLInstance *sin, uint64_t cookie)
+static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie)
 {
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
     uint32_t current_async;
 
     qemu_mutex_lock(&qxl->async_lock);
     current_async = qxl->current_async;
     qxl->current_async = QXL_UNDEFINED_IO;
     qemu_mutex_unlock(&qxl->async_lock);
+    dprint(qxl, 2, "async_complete: %d (%p) done\n", current_async, cookie);
+    if (current_async != cookie->io) {
+        fprintf(stderr, "qxl: %s: error: current_async = %d != %ld = cookie->io\n",
+                __func__, current_async, cookie->io);
+    }
 
-    dprint(qxl, 2, "async_complete: %d (%ld) done\n", current_async, cookie);
     switch (current_async) {
     case QXL_IO_CREATE_PRIMARY_ASYNC:
         qxl_create_guest_primary_complete(qxl);
@@ -757,12 +769,28 @@  static void interface_async_complete(QXLInstance *sin, uint64_t cookie)
         qxl_spice_destroy_surfaces_complete(qxl);
         break;
     case QXL_IO_DESTROY_SURFACE_ASYNC:
-        qxl_spice_destroy_surface_wait_complete(qxl, (uint32_t)cookie);
+        qxl_spice_destroy_surface_wait_complete(qxl, (uint32_t)cookie->data);
         break;
     }
     qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD);
 }
 
+/* called from spice server thread context only */
+static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    QXLCookie *cookie = (QXLCookie*)cookie_token;
+
+    switch (cookie->type) {
+    case QXL_COOKIE_TYPE_IO:
+        interface_async_complete_io(qxl, cookie);
+        break;
+    default:
+        fprintf(stderr, "qxl: %s: unexpected cookie type %d\n", __func__, cookie->type);
+    }
+    g_free(cookie);
+}
+
 #endif
 
 static const QXLInterface qxl_interface = {
@@ -1077,9 +1105,7 @@  static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async)
     if (d->mode == QXL_MODE_UNDEFINED) {
         return 0;
     }
-
     dprint(d, 1, "%s\n", __FUNCTION__);
-
     d->mode = QXL_MODE_UNDEFINED;
     qemu_spice_destroy_primary_surface(&d->ssd, 0, async);
     qxl_spice_reset_cursor(d);
@@ -1215,7 +1241,7 @@  async_common:
     {
         QXLRect update = d->ram->update_area;
         qxl_spice_update_area(d, d->ram->update_surface,
-                              &update, NULL, 0, 0, async);
+                              &update, NULL, 0, 0, async, NULL);
         break;
     }
     case QXL_IO_NOTIFY_CMD:
diff --git a/hw/qxl.h b/hw/qxl.h
index 766aa6d..666dd78 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -118,7 +118,7 @@  void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
                            struct QXLRect *area, struct QXLRect *dirty_rects,
                            uint32_t num_dirty_rects,
                            uint32_t clear_dirty_region,
-                           qxl_async_io async);
+                           qxl_async_io async, QXLCookie *cookie);
 void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
                                uint32_t count);
 void qxl_spice_oom(PCIQXLDevice *qxl);
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 6c302a3..680e6f4 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -60,12 +60,26 @@  void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
     dest->right = MAX(dest->right, r->right);
 }
 
+QXLCookie *qxl_cookie_new(int type, uint64_t io, uint64_t data)
+{
+    QXLCookie *cookie;
+
+    cookie = g_malloc0(sizeof(*cookie));
+    cookie->type = type;
+    cookie->io = io;
+    cookie->data = data;
+    return cookie;
+}
+
 void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot,
                             qxl_async_io async)
 {
     if (async != QXL_SYNC) {
 #if SPICE_INTERFACE_QXL_MINOR >= 1
-        spice_qxl_add_memslot_async(&ssd->qxl, memslot, 0);
+        spice_qxl_add_memslot_async(&ssd->qxl, memslot,
+                (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                         QXL_IO_MEMSLOT_ADD_ASYNC,
+                                         0));
 #else
         abort();
 #endif
@@ -85,7 +99,10 @@  void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
 {
     if (async != QXL_SYNC) {
 #if SPICE_INTERFACE_QXL_MINOR >= 1
-        spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, 0);
+        spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface,
+                (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                         QXL_IO_CREATE_PRIMARY_ASYNC,
+                                         0));
 #else
         abort();
 #endif
@@ -100,7 +117,10 @@  void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd,
 {
     if (async != QXL_SYNC) {
 #if SPICE_INTERFACE_QXL_MINOR >= 1
-        spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, 0);
+        spice_qxl_destroy_primary_surface_async(&ssd->qxl, id,
+                (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                         QXL_IO_DESTROY_PRIMARY_ASYNC,
+                                         0));
 #else
         abort();
 #endif
diff --git a/ui/spice-display.h b/ui/spice-display.h
index 5e52df9..c8747ab 100644
--- a/ui/spice-display.h
+++ b/ui/spice-display.h
@@ -48,6 +48,18 @@  typedef enum qxl_async_io {
     QXL_ASYNC,
 } qxl_async_io;
 
+enum {
+    QXL_COOKIE_TYPE_IO,
+};
+
+typedef struct QXLCookie {
+    int      type;
+    uint64_t io;
+    uint64_t data;
+} QXLCookie;
+
+QXLCookie *qxl_cookie_new(int type, uint64_t io, uint64_t data);
+
 typedef struct SimpleSpiceDisplay SimpleSpiceDisplay;
 typedef struct SimpleSpiceUpdate SimpleSpiceUpdate;