[Spice-devel] [PATCH spice-server v5 1/8] stream-device: Avoid device to get stuck if multiple messages are batched

Frediano Ziglio fziglio at redhat.com
Tue Feb 13 15:54:14 UTC 2018


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 at redhat.com>
---
 server/stream-device.c | 29 ++++++++++++++++++++++++-----
 1 file changed, 24 insertions(+), 5 deletions(-)

diff --git a/server/stream-device.c b/server/stream-device.c
index 4eaa959b..3a7cb306 100644
--- a/server/stream-device.c
+++ b/server/stream-device.c
@@ -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;
 }
 
-- 
2.14.3



More information about the Spice-devel mailing list