[Spice-devel] [PATCH v2 3/4] worker: avoid blocking loop

Frediano Ziglio fziglio at redhat.com
Wed Feb 3 11:48:24 CET 2016


Make sure we process commands after we can send data to client.
If during processing we detected that there was too much data in the
clients queues the processing of commands just stop till the next
iteration.
However if all data are pushed in a single iteration of the loop
and commands were already processed there was the (remote) possibility
that the loop hangs till a separate event (like a screen resize on
client window) arrive.
I manage to reproduce and after half an hour no events arrived.
This patch detect that processing was stuck and now we can process new
commands and force a new iteration.

Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
Acked-by: Jonathon Jongsma <jjongsma at redhat.com>
---
 server/red-worker.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/server/red-worker.c b/server/red-worker.c
index 031350a..45a597f 100644
--- a/server/red-worker.c
+++ b/server/red-worker.c
@@ -69,6 +69,7 @@ struct RedWorker {
 
     DisplayChannel *display_channel;
     uint32_t display_poll_tries;
+    gboolean was_blocked;
 
     CursorChannel *cursor_channel;
     uint32_t cursor_poll_tries;
@@ -196,6 +197,7 @@ static int red_process_cursor(RedWorker *worker, int *ring_is_empty)
         }
         n++;
     }
+    worker->was_blocked = TRUE;
     return n;
 }
 
@@ -318,9 +320,16 @@ static int red_process_display(RedWorker *worker, int *ring_is_empty)
             return n;
         }
     }
+    worker->was_blocked = TRUE;
     return n;
 }
 
+static bool red_process_is_blocked(RedWorker *worker)
+{
+    return red_channel_max_pipe_size(RED_CHANNEL(worker->cursor_channel)) > MAX_PIPE_SIZE ||
+           red_channel_max_pipe_size(RED_CHANNEL(worker->display_channel)) > MAX_PIPE_SIZE;
+}
+
 static void red_disconnect_display(RedWorker *worker)
 {
     spice_warning("update timeout");
@@ -1416,6 +1425,10 @@ static gboolean worker_source_prepare(GSource *source, gint *p_timeout)
     if (*p_timeout == 0)
         return TRUE;
 
+    if (worker->was_blocked && !red_process_is_blocked(worker)) {
+        return TRUE;
+    }
+
     return FALSE;
 }
 
@@ -1445,6 +1458,7 @@ static gboolean worker_source_dispatch(GSource *source, GSourceFunc callback,
     stream_timeout(display);
 
     worker->event_timeout = INF_EVENT_WAIT;
+    worker->was_blocked = FALSE;
     red_process_cursor(worker, &ring_is_empty);
     red_process_display(worker, &ring_is_empty);
 
-- 
2.4.3



More information about the Spice-devel mailing list