[Spice-devel] [PATCH spice-server v4 1/4] stream-device: Avoid device to get stuck if multiple messages are batched
Frediano Ziglio
fziglio at redhat.com
Fri Feb 9 15:22:10 UTC 2018
>
> On Mon, 2018-01-15 at 09:10 +0000, Frediano Ziglio wrote:
> > If messages are sent together by the agent the device is reading
> > only part of the data. This cause Qemu to not poll for new data and
> > stream_device_read_msg_from_dev won't be called again.
> > This can cause a stall. To avoid this continue handling data
> > after a full message was processed.
>
> So I think that this commit message is a little bit misleading. The
> "stall" is caused because it seems that we're not really implementing
> the RedCharDevice class as expected.
>
> stream_device_read_msg_from_dev() is the vfunc implementation of
> RedCharDevice::read_one_msg_from_device(). This function expects the
> implementation to read to the end of a single message and then return a
> RedPipeItem* to be sent out to clients. If a non-NULL RedPipeItem* is
> returned, red_char_device_read_from_device() sends that pipe item to
> all clients and then continues looping and tries to read another
> message from the device. However, if read_one_msg_from_device() returns
> a NULL RedPipeItem*, it apparently assumes that there was not enough
> data for a full message and there is nothing else to read, so it breaks
> out of the loop.
>
> Our StreamDevice vfunc always returns NULL from
> read_one_msg_from_device() because we handle the messages directly
> rather then returning RedPipeItems to be sent on to a client. But this
> means that RedCharDevice apparently thinks that we were not able to
> read a full message from the device so it stops its loop.
>
> So calling red_char_device_wakeup() here seems a bit like a hack. It
> ends up recursively calling red_char_device_read_from_device(). Reading
> through some of the other RedCharDevice implementations, it seems like
> we've solved this issue in other ways already. For instance
> vdi_port_read_one_msg_from_device() reads a full message and then
> determines whether it should be sent to the client or not. If it
> should, it returns a RedPipeItem. But if it shouldn't be sent to the
> client, it loops around and tries to read the next message. In other
> words, this function doesn't necessarily just read one message. It
> reads as many messages as necessary until it comes to a message that
> should be sent to the client (or until it runs out of data to read).
> But this behavior sort of duplicates the logic in the
> red_char_device_read_from_device() function that calls this function.
>
> Maybe a better way to handle this is to change the
> RedCharDevice::read_one_msg_from_device() vfunc to allow us to handle
> this use case.
>
> For instance, instead of:
>
> RedPipeItem* (*read_one_msg_from_device)(RedCharDevice *self,
> SpiceCharDeviceInstance
> *sin);
>
> It could be something like:
>
> bool (*read_one_msg_from_device)(RedCharDevice *self,
> SpiceCharDeviceInstance *sin,
> RedPipeItem **out_item);
>
> This way we could handle 3 different scenarios:
> - return true and set *out_item to a new pipe item that should be sent
> to the client
> - return true and leave out_item NULL to indicate that we read a
> message but there is nothing to be sent to the client.
> - return false to indicate that there was not enough data available to
> read a full message
>
>
I think another solution instead of calling red_char_device_wakeup inside
stream_device_read_msg_from_dev would be to create a loop (maybe using a
wrapper function).
Frediano
>
>
> >
> > Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
> > ---
> > server/stream-device.c | 9 +++++++++
> > 1 file changed, 9 insertions(+)
> >
> > diff --git a/server/stream-device.c b/server/stream-device.c
> > index 4eaa959b..897fc665 100644
> > --- a/server/stream-device.c
> > +++ b/server/stream-device.c
> > @@ -123,6 +123,15 @@ stream_device_read_msg_from_dev(RedCharDevice
> > *self, SpiceCharDeviceInstance *si
> > dev->hdr_pos = 0;
> > }
> >
> > + if (handled || dev->has_error) {
> > + // Qemu put the device on blocking state if we don't read
> > all data
> > + // so schedule another read.
> > + // We arrive here if we processed that entire message or we
> > + // got an error, try to read another message or discard the
> > + // wrong data
> > + red_char_device_wakeup(self);
> > + }
> > +
> > return NULL;
> > }
> >
>
More information about the Spice-devel
mailing list