From 916e48e331012d4f7d18cdd68bad1bf7551c08ee Mon Sep 17 00:00:00 2001 From: Frediano Ziglio Date: Thu, 28 Jan 2016 23:51:17 +0000 Subject: [PATCH] worker: avoid blocking loop 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 Acked-by: Jonathon Jongsma --- server/red-worker.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/server/red-worker.c b/server/red-worker.c index 0d91eac5..fbf5fa65 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);