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

Frediano Ziglio fziglio at redhat.com
Fri Jan 29 02:53:50 PST 2016


Make sure we process commands after we can send data to client.
If during processing we detected that there was too 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 were 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>
---
 server/red-worker.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/server/red-worker.c b/server/red-worker.c
index cf8e73d..8c79628 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;
+    bool 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