stream-device: Avoid device to get stuck if multiple messages are batched

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.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
This commit is contained in:
Frediano Ziglio 2018-01-11 11:41:49 +00:00
parent fac12737d5
commit ebdda84dc1

View File

@ -71,16 +71,15 @@ static StreamMsgHandler handle_msg_format, handle_msg_data;
static bool handle_msg_invalid(StreamDevice *dev, SpiceCharDeviceInstance *sin,
const char *error_msg) SPICE_GNUC_WARN_UNUSED_RESULT;
static RedPipeItem *
stream_device_read_msg_from_dev(RedCharDevice *self, SpiceCharDeviceInstance *sin)
static bool
stream_device_partial_read(StreamDevice *dev, SpiceCharDeviceInstance *sin)
{
StreamDevice *dev = STREAM_DEVICE(self);
SpiceCharDeviceInterface *sif;
int n;
bool handled = false;
if (dev->has_error || dev->flow_stopped || !dev->stream_channel) {
return NULL;
return false;
}
sif = spice_char_device_get_interface(sin);
@ -89,7 +88,7 @@ stream_device_read_msg_from_dev(RedCharDevice *self, SpiceCharDeviceInstance *si
while (dev->hdr_pos < sizeof(dev->hdr)) {
n = sif->read(sin, (uint8_t *) &dev->hdr + dev->hdr_pos, sizeof(dev->hdr) - dev->hdr_pos);
if (n <= 0) {
return NULL;
return false;
}
dev->hdr_pos += n;
if (dev->hdr_pos >= sizeof(dev->hdr)) {
@ -123,6 +122,26 @@ 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
return true;
}
return false;
}
static RedPipeItem *
stream_device_read_msg_from_dev(RedCharDevice *self, SpiceCharDeviceInstance *sin)
{
StreamDevice *dev = STREAM_DEVICE(self);
while (stream_device_partial_read(dev, sin)) {
continue;
}
return NULL;
}