[Spice-devel] [PATCH 05/14] reds: Derive VDIPortReadBuf from RedPipeItem

Jonathon Jongsma jjongsma at redhat.com
Mon Apr 11 21:02:20 UTC 2016


On Thu, 2016-04-07 at 17:11 -0500, Jonathon Jongsma wrote:
> From: Christophe Fergeau <cfergeau at redhat.com>
> 
> Since RedPipeItem is already refcounted, this allows to remove various
> layers of ref/unref helpers from reds.c, and use the generic
> red_pipe_item_{ref, unref} instead.

Hmm, I don't know if I like making this a RedPipeItem just to get the
refcounting. It seems like it would be better to simply return an actual pipe
item (e.g. AgentDataPipeItem) rather than VDIReadBuf from
read_one_msg_from_device(). That would match the other char device
implementations more closely as well...


> ---
>  server/reds.c | 67 +++++++++++++++++++++++++++-------------------------------
> -
>  1 file changed, 31 insertions(+), 36 deletions(-)
> 
> diff --git a/server/reds.c b/server/reds.c
> index 1c37627..64f7df8 100644
> --- a/server/reds.c
> +++ b/server/reds.c
> @@ -167,8 +167,7 @@ struct ChannelSecurityOptions {
>  };
>  
>  typedef struct VDIReadBuf {
> -    RingItem link;
> -    uint32_t refs;
> +    RedPipeItem link;

If we do take this approach, I don't think that this should still be named
'link'. That's rather confusing.


Reviewed-by: Jonathon Jongsma <jjongsma at redhat.com>


>      RedCharDeviceVDIPort *dev;
>  
>      int len;
> @@ -265,8 +264,6 @@ static uint32_t reds_qxl_ram_size(RedsState *reds);
>  static int calc_compression_level(RedsState *reds);
>  
>  static VDIReadBuf *vdi_port_get_read_buf(RedCharDeviceVDIPort *dev);
> -static VDIReadBuf *vdi_port_read_buf_ref(VDIReadBuf *buf);
> -static void vdi_port_read_buf_unref(VDIReadBuf *buf);
>  
>  static ChannelSecurityOptions *reds_find_channel_security(RedsState *reds,
> int id)
>  {
> @@ -486,7 +483,7 @@ static void reds_reset_vdp(RedsState *reds)
>      dev->priv->receive_len = sizeof(dev->priv->vdi_chunk_header);
>      dev->priv->message_receive_len = 0;
>      if (dev->priv->current_read_buf) {
> -        vdi_port_read_buf_unref(dev->priv->current_read_buf);
> +        red_pipe_item_unref(dev->priv->current_read_buf);
>          dev->priv->current_read_buf = NULL;
>      }
>      /* Reset read filter to start with clean state when the agent reconnects
> */
> @@ -705,15 +702,11 @@ static void reds_agent_remove(RedsState *reds)
>      }
>  }
>  
> -/*******************************
> - * Char device state callbacks *
> - * *****************************/
> -
>  static void vdi_port_read_buf_release(uint8_t *data, void *opaque)
>  {
>      VDIReadBuf *buf = (VDIReadBuf *)opaque;
>  
> -    vdi_port_read_buf_unref(buf);
> +    red_pipe_item_unref(buf);
>  }
>  
>  /* returns TRUE if the buffer can be forwarded */
> @@ -756,32 +749,25 @@ static VDIReadBuf
> *vdi_port_get_read_buf(RedCharDeviceVDIPort *dev)
>      }
>  
>      ring_remove(item);
> -    buf = SPICE_CONTAINEROF(item, VDIReadBuf, link);
> +    buf = SPICE_CONTAINEROF(item, VDIReadBuf, link.parent.link);
>  
> -    buf->refs = 1;
> -    return buf;
> -}
> +    g_warn_if_fail(buf->link.refcount == 0);
> +    red_pipe_item_ref(buf);
>  
> -static VDIReadBuf* vdi_port_read_buf_ref(VDIReadBuf *buf)
> -{
> -    buf->refs++;
>      return buf;
>  }
>  
> -/* FIXME: refactor so that unreffing the VDIReadBuf doesn't require accessing
> - * RedsState? */
> -static void vdi_port_read_buf_unref(VDIReadBuf *buf)
> +static void vdi_port_read_buf_free(VDIReadBuf *buf)
>  {
> -    if (!--buf->refs) {
> -        ring_add(&buf->dev->priv->read_bufs, &buf->link);
> +    g_warn_if_fail(buf->link.refcount == 0);
> +    ring_add(&buf->dev->priv->read_bufs, (RingItem *)buf);
>  
> -        /* read_one_msg_from_vdi_port may have never completed because the
> read_bufs
> -        ring was empty. So we call it again so it can complete its work if
> -        necessary. Note that since we can be called from
> red_char_device_wakeup
> -        this can cause recursion, but we have protection for that */
> -        if (buf->dev->priv->agent_attached) {
> -            red_char_device_wakeup(RED_CHAR_DEVICE(buf->dev));
> -        }
> +    /* read_one_msg_from_vdi_port may have never completed because the
> read_bufs
> +       ring was empty. So we call it again so it can complete its work if
> +       necessary. Note that since we can be called from
> red_char_device_wakeup
> +       this can cause recursion, but we have protection for that */
> +    if (buf->dev->priv->agent_attached) {
> +       red_char_device_wakeup(RED_CHAR_DEVICE(buf->dev));
>      }
>  }
>  
> @@ -851,7 +837,7 @@ static RedCharDeviceMsgToClient
> *vdi_port_read_one_msg_from_device(SpiceCharDevi
>                  if (error) {
>                      reds_agent_remove(reds);
>                  }
> -                vdi_port_read_buf_unref(dispatch_buf);
> +                red_pipe_item_unref(dispatch_buf);
>              }
>          }
>          } /* END switch */
> @@ -866,11 +852,12 @@ static void
> vdi_port_send_msg_to_client(RedCharDeviceMsgToClient *msg,
>  {
>      VDIReadBuf *agent_data_buf = msg;
>  
> +    red_pipe_item_ref(agent_data_buf);
>      main_channel_client_push_agent_data(red_client_get_main(client),
>                                          agent_data_buf->data,
>                                          agent_data_buf->len,
>                                          vdi_port_read_buf_release,
> -                                       
>  vdi_port_read_buf_ref(agent_data_buf));
> +                                        agent_data_buf);
>  }
>  
>  static void vdi_port_send_tokens_to_client(RedClient *client, uint32_t
> tokens, void *opaque)
> @@ -1220,7 +1207,7 @@ void reds_on_main_channel_migrate(RedsState *reds,
> MainChannelClient *mcc)
>              if (error) {
>                 reds_agent_remove(reds);
>              }
> -            vdi_port_read_buf_unref(read_buf);
> +            red_pipe_item_unref(read_buf);
>          }
>  
>          spice_assert(agent_dev->priv->receive_len);
> @@ -4292,8 +4279,16 @@ red_char_device_vdi_port_init(RedCharDeviceVDIPort
> *self)
>      for (i = 0; i < REDS_VDI_PORT_NUM_RECEIVE_BUFFS; i++) {
>          VDIReadBuf *buf = spice_new0(VDIReadBuf, 1);
>          buf->dev = self;
> -        ring_item_init(&buf->link);
> -        ring_add(&self->priv->read_bufs, &buf->link);
> +        /* Bogus pipe item type, we only need the RingItem and refcounting
> +         * from the base class and are not going to use the type
> +         */
> +        red_pipe_item_init(&buf->link, -1,
> +                           (GDestroyNotify)vdi_port_read_buf_free);
> +        g_warn_if_fail(!self->priv->agent_attached);
> +        /* This ensures the newly created buffer is placed in the
> +         * RedCharDeviceVDIPort::read_bufs queue ready to be reused
> +         */
> +        red_pipe_item_unref(buf);
>      }
>  }
>  
> @@ -4318,8 +4313,8 @@
> red_char_device_vdi_port_class_init(RedCharDeviceVDIPortClass *klass)
>      object_class->constructed = red_char_device_vdi_port_constructed;
>  
>      char_dev_class->read_one_msg_from_device =
> vdi_port_read_one_msg_from_device;
> -    char_dev_class->ref_msg_to_client =
> (RedCharDeviceRefMsgToClient)vdi_port_read_buf_ref;
> -    char_dev_class->unref_msg_to_client =
> (RedCharDeviceUnrefMsgToClient)vdi_port_read_buf_unref;
> +    char_dev_class->ref_msg_to_client =
> (RedCharDeviceRefMsgToClient)red_pipe_item_ref;
> +    char_dev_class->unref_msg_to_client =
> (RedCharDeviceUnrefMsgToClient)red_pipe_item_unref;
>      char_dev_class->send_msg_to_client = vdi_port_send_msg_to_client;
>      char_dev_class->send_tokens_to_client = vdi_port_send_tokens_to_client;
>      char_dev_class->remove_client = vdi_port_remove_client;


More information about the Spice-devel mailing list