[Spice-devel] [spice-server 03/10] Remove OutgoingHandlerInterface

Frediano Ziglio fziglio at redhat.com
Fri Feb 10 15:36:10 UTC 2017


> 
> On Fri, Feb 10, 2017 at 04:47:15AM -0500, Frediano Ziglio wrote:
> > > 
> > > On Tue, 2017-02-07 at 11:59 +0100, Christophe Fergeau wrote:
> > > > RedChannel uses OutgoingHandlerInterface to provide constant pointers
> > > > to
> > > > RedChannelClient methods. This OutgoingHandlerInterface structure is
> > > > then used in RedChannelClient to indirectly call these methods.
> > > > 
> > > > Since the content of OutgoingHandlerInterface is never modified, we
> > > > can
> > > > directly call the relevant methods and make them static.
> > 
> > See my comment on 00/10. The reason is that mostly is a broken
> > unused abstraction, that's nothing wrong in the abstract concept
> > itself.
> 
> I'll replace "Since the content of OutgoingHandlerInterface is never
> modified, we can
> directly call the relevant methods and make them static."
> 
> with
> 
> "The OutgoingHandlerInterface abstraction is unused, ie the codebase
> only has a single implementation for it, so we can directly call the
> relevant methods and make them static instead", does that read better to
> you?
> 

Sure. Not only unused, even badly defined.

> 
> > 
> > > > ---
> > > >  server/red-channel-client-private.h |  1 -
> > > >  server/red-channel-client.c         | 30 ++++++++++++++++-----------
> > > > ---
> > > >  server/red-channel-client.h         |  6 ------
> > > >  server/red-channel.c                | 13 -------------
> > > >  server/red-channel.h                | 20 +-------------------
> > > >  5 files changed, 17 insertions(+), 53 deletions(-)
> > > > 
> > > > diff --git a/server/red-channel-client-private.h b/server/red-
> > > > channel-client-private.h
> > > > index d01cdbd..5d29f32 100644
> > > > --- a/server/red-channel-client-private.h
> > > > +++ b/server/red-channel-client-private.h
> > > > @@ -41,7 +41,6 @@ typedef struct RedChannelClientConnectivityMonitor
> > > > {
> > > >  } RedChannelClientConnectivityMonitor;
> > > >  
> > > >  typedef struct OutgoingHandler {
> > > > -    OutgoingHandlerInterface *cb;
> > > >      void *opaque;
> > > >      struct iovec vec_buf[IOV_MAX];
> > > >      int vec_size;
> > > 
> > > So, after removing the 'cb' field here, we're basically left with some
> > > buffers. In my mind, that makes OutgoingHandler a bit of a misnomer.
> > > Perhaps we could rename it to something that describes its function a
> > > bit better?
> > > 
> > 
> > I would place a TODO then. I would wait to remove the opaque (some patch
> > later) before renaming. About name... OutgoingMessageBuffer ?
> 
> I picked that name and queued that at the end of this series (together
> with removing red-channel-client-private.h)
> 

Yes, that header is just included by red-channel-client.c so not
hard to remove, just inline it :)

> > > > -void red_channel_client_on_output(void *opaque, int n)
> > > > +static void red_channel_client_on_output(void *opaque, int n)
> > > >  {
> > > >      RedChannelClient *rcc = opaque;
> > > >      RedChannel *channel = red_channel_client_get_channel(rcc);
> > > > @@ -381,6 +380,7 @@ void red_channel_client_on_output(void *opaque,
> > > > int n)
> > > >      if (rcc->priv->connectivity_monitor.timer) {
> > > >          rcc->priv->connectivity_monitor.out_bytes += n;
> > > >      }
> > > > +    /* FIXME: use a signal rather than a hardcoded call to a
> > > > RedChannel callback? */
> > > 
> > > That sounds nicer to me. That would remove the need to expose this from
> > > the header (as I mentioned in the review for the last patch)
> > > 
> > 
> > That sound ugly. Why hiding a dependency into a binary dynamic form
> > is better?
> 
> red_channel_on_output() is currently used for statistics gathering purpose.
> I do not see much value in hardcoding that RedChannel is gathering
> statistics for RedChannelClient in the code. Emitting a signal instead
> remove this coupling, and makes things more flexible with respect to
> what exact class is going to implement the statistics gathering (aka
> observer pattern if I'm not mistaken ?)
> 

So are you saying you prefer an heavy unsafe signal instead of a
function call just for statistics that's disabled by default?
Actually is weird considering lot of these patches are removing
callbacks and indirection.
I don't see much problems if RedChannelClient do some statistics,
I was thinking something like

static void red_channel_client_on_output(RedChannelClient *rcc, int n)
{
    if (rcc->priv->connectivity_monitor.timer) {
        rcc->priv->connectivity_monitor.out_bytes += n;
    }
    stat_inc_counter(whatever_works, rcc->priv->out_bytes_counter, n);
}

<OT>
Why we need to update a byte count for monitoring?
Is there no such statistics in RedsStream ?
</OT>

> > 
> > > >      red_channel_on_output(channel, n);
> > > >  }
> > > >  
> > > > @@ -393,15 +393,15 @@ void red_channel_client_on_input(void *opaque,
> > > > int n)
> > > >      }
> > > >  }
> > > >  
> > > > -int red_channel_client_get_out_msg_size(void *opaque)
> > > > +static int red_channel_client_get_out_msg_size(void *opaque)
> > > >  {
> > > >      RedChannelClient *rcc = RED_CHANNEL_CLIENT(opaque);
> > > >  
> > > >      return rcc->priv->send_data.size;
> > > >  }
> > > >  
> > > > -void red_channel_client_prepare_out_msg(void *opaque, struct iovec
> > > > *vec,
> > > > -                                        int *vec_size, int pos)
> > > > +static void red_channel_client_prepare_out_msg(void *opaque, struct
> > > > iovec *vec,
> > > > +                                               int *vec_size, int
> > > > pos)
> > > >  {
> > > >      RedChannelClient *rcc = RED_CHANNEL_CLIENT(opaque);
> > > >  
> > > > @@ -409,7 +409,7 @@ void red_channel_client_prepare_out_msg(void
> > > > *opaque, struct iovec *vec,
> > > >                                              vec, IOV_MAX, pos);
> > > >  }
> > > >  
> > > > -void red_channel_client_on_out_block(void *opaque)
> > > > +static void red_channel_client_on_out_block(void *opaque)
> > > >  {
> > > >      SpiceCoreInterfaceInternal *core;
> > > >      RedChannelClient *rcc = RED_CHANNEL_CLIENT(opaque);
> > > > @@ -549,7 +549,7 @@ static void
> > > > red_channel_client_restore_main_sender(RedChannelClient *rcc)
> > > >      rcc->priv->send_data.header.data = rcc->priv-
> > > > >send_data.main.header_data;
> > > >  }
> > > >  
> > > > -void red_channel_client_on_out_msg_done(void *opaque)
> > > > +static void red_channel_client_on_out_msg_done(void *opaque)
> > > >  {
> > > >      RedChannelClient *rcc = RED_CHANNEL_CLIENT(opaque);
> > > >      int fd;
> > > > @@ -1010,33 +1010,35 @@ static void
> > > > red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handle
> > > >  
> > > >      if (handler->size == 0) {
> > > >          handler->vec = handler->vec_buf;
> > > > -        handler->size = handler->cb->get_msg_size(handler->opaque);
> > > > +        handler->size = red_channel_client_get_out_msg_size(handler-
> > > > >opaque);
> > > >          if (!handler->size) {  // nothing to be sent
> > > >              return;
> > > >          }
> > > >      }
> > > >  
> > > >      for (;;) {
> > > > -        handler->cb->prepare(handler->opaque, handler->vec,
> > > > &handler->vec_size, handler->pos);
> > > > +        red_channel_client_prepare_out_msg(handler->opaque, handler-
> > > > >vec, &handler->vec_size, handler->pos);
> > > >          n = reds_stream_writev(stream, handler->vec, handler-
> > > > >vec_size);
> > > >          if (n == -1) {
> > > >              switch (errno) {
> > > >              case EAGAIN:
> > > > -                handler->cb->on_block(handler->opaque);
> > > > +                red_channel_client_on_out_block(handler->opaque);
> > 
> > Maybe these function should be renamed too. Not much sense to
> > still call them _on_<something> while we know what we want them
> > to do. We are removing the abstraction.
> > Why not red_channel_client_set_blocked ?
> 
> Ah, did not really give any thoughts about that, I can look into
> renaming them indeed, thanks for the name suggestions!
> 
> > 
> > > >                  return;
> > > >              case EINTR:
> > > >                  continue;
> > > >              case EPIPE:
> > > > -                handler->cb->on_error(handler->opaque);
> > > > +                /* FIXME: handle disconnection in caller */
> > 
> > What's this FIXME about ?
> 
> Ah, this got Jonathon confused later on too, my feeling is that things
> would look better as:
> 
> int status = red_peer_handle_outgoing(..)
> switch (status) {
>     case 0:
>         red_channel_client_on_out_msg_done(red_channel_client);
>         break;
>     case EPIPE:
>     default:
>         red_channel_disconnect(red_channel_client);
>         break;
> }
> 
> and limit as much as possible calls to red_channel_client_xxx from
> red_peer_handle_outgoing(). Did not explore this yet, so cannot tell
> if it makes sense or not :)
> 
> Christophe
> 

Now that the function does a lot direct calls I don't see much sense.
Maybe you can use a kernel style label + error handling code?
In this function there are just 2 calls to red_channel_disconnect.

I was confused by the FIXME which is quite strong (I usually use TODO
if I can improve something, FIXME for possible bugs to fix ASAP) and
that adding make think that the problem was not present before the
patch (that is a regression introduced).

Frediano


More information about the Spice-devel mailing list