[Spice-devel] [PATCH v2 1/4] worker: push data when clients can receive them
Jonathon Jongsma
jjongsma at redhat.com
Wed Feb 3 16:47:43 CET 2016
Acked-by: Jonathon Jongsma <jjongsma at redhat.com>
On Wed, 2016-02-03 at 10:48 +0000, Frediano Ziglio wrote:
> During every iteration of the main worker loop, outgoing data was pushed to
> the client. However, there was no guarantee that the loop would be woken up
> in every situation. So there were some conditions where the loop would stop
> iterating until a new event was sent.
>
> Currently, the events that can wake up the main worker loop include:
> - data from dispatcher (including wakeups from the guest)
> - data from clients
> - timeouts on a stream
> - other timeouts
> - polling
>
> This patch adds a new wakeup event: when we have items that are queued to
> be sent to a client, we set up a watch event for writing data to the
> client. If no items are waiting to be sent, this watch will be disabled.
> This allows us to remove the explicit push from the main worker loop.
>
> This has some advantages:
> - it could lower latency as we don't have to wait for a polling timeout.
> From my experiments using a tight loop (so not really the ideal
> condition to see the improvements) the total time was reduced by 2-3%)
> - helps reduce the possibility of hanging loops
> - avoids having to scan all clients to detect which one can accept data.
>
> Signed-by: Frediano Ziglio <figlio at redhat.com>
> ---
> server/red-channel.c | 39 ++++++++++++++++++---------------------
> server/red-worker.c | 13 -------------
> 2 files changed, 18 insertions(+), 34 deletions(-)
>
> diff --git a/server/red-channel.c b/server/red-channel.c
> index 33d4158..fdd85b9 100644
> --- a/server/red-channel.c
> +++ b/server/red-channel.c
> @@ -1359,6 +1359,11 @@ void red_channel_client_push(RedChannelClient *rcc)
> while ((pipe_item = red_channel_client_pipe_item_get(rcc))) {
> red_channel_client_send_item(rcc, pipe_item);
> }
> + if (red_channel_client_no_item_being_sent(rcc) && ring_is_empty(&rcc
> ->pipe)
> + && rcc->stream->watch) {
> + rcc->channel->core->watch_update_mask(rcc->stream->watch,
> + SPICE_WATCH_EVENT_READ);
> + }
> rcc->during_send = FALSE;
> red_channel_client_unref(rcc);
> }
> @@ -1659,7 +1664,7 @@ void red_channel_pipe_item_init(RedChannel *channel,
> PipeItem *item, int type)
> item->type = type;
> }
>
> -static inline int validate_pipe_add(RedChannelClient *rcc, PipeItem *item)
> +static inline gboolean client_pipe_add(RedChannelClient *rcc, PipeItem *item,
> RingItem *pos)
> {
> spice_assert(rcc && item);
> if (SPICE_UNLIKELY(!red_channel_client_is_connected(rcc))) {
> @@ -1667,17 +1672,20 @@ static inline int validate_pipe_add(RedChannelClient
> *rcc, PipeItem *item)
> red_channel_client_release_item(rcc, item, FALSE);
> return FALSE;
> }
> + if (ring_is_empty(&rcc->pipe) && rcc->stream->watch) {
> + rcc->channel->core->watch_update_mask(rcc->stream->watch,
> + SPICE_WATCH_EVENT_READ |
> + SPICE_WATCH_EVENT_WRITE);
> + }
> + rcc->pipe_size++;
> + ring_add(pos, &item->link);
> return TRUE;
> }
>
> void red_channel_client_pipe_add(RedChannelClient *rcc, PipeItem *item)
> {
>
> - if (!validate_pipe_add(rcc, item)) {
> - return;
> - }
> - rcc->pipe_size++;
> - ring_add(&rcc->pipe, &item->link);
> + client_pipe_add(rcc, item, &rcc->pipe);
> }
>
> void red_channel_client_pipe_add_push(RedChannelClient *rcc, PipeItem *item)
> @@ -1690,11 +1698,7 @@ void red_channel_client_pipe_add_after(RedChannelClient
> *rcc,
> PipeItem *item, PipeItem *pos)
> {
> spice_assert(pos);
> - if (!validate_pipe_add(rcc, item)) {
> - return;
> - }
> - rcc->pipe_size++;
> - ring_add_after(&item->link, &pos->link);
> + client_pipe_add(rcc, item, &pos->link);
> }
>
> int red_channel_client_pipe_item_is_linked(RedChannelClient *rcc,
> @@ -1706,21 +1710,14 @@ int
> red_channel_client_pipe_item_is_linked(RedChannelClient *rcc,
> void red_channel_client_pipe_add_tail_no_push(RedChannelClient *rcc,
> PipeItem *item)
> {
> - if (!validate_pipe_add(rcc, item)) {
> - return;
> - }
> - rcc->pipe_size++;
> - ring_add_before(&item->link, &rcc->pipe);
> + client_pipe_add(rcc, item, rcc->pipe.prev);
> }
>
> void red_channel_client_pipe_add_tail(RedChannelClient *rcc, PipeItem *item)
> {
> - if (!validate_pipe_add(rcc, item)) {
> - return;
> + if (client_pipe_add(rcc, item, rcc->pipe.prev)) {
> + red_channel_client_push(rcc);
> }
> - rcc->pipe_size++;
> - ring_add_before(&item->link, &rcc->pipe);
> - red_channel_client_push(rcc);
> }
>
> void red_channel_client_pipe_add_type(RedChannelClient *rcc, int
> pipe_item_type)
> diff --git a/server/red-worker.c b/server/red-worker.c
> index f6c4f45..031350a 100644
> --- a/server/red-worker.c
> +++ b/server/red-worker.c
> @@ -321,16 +321,6 @@ static int red_process_display(RedWorker *worker, int
> *ring_is_empty)
> return n;
> }
>
> -static void red_push(RedWorker *worker)
> -{
> - if (worker->cursor_channel) {
> - red_channel_push(RED_CHANNEL(worker->cursor_channel));
> - }
> - if (worker->display_channel) {
> - red_channel_push(RED_CHANNEL(worker->display_channel));
> - }
> -}
> -
> static void red_disconnect_display(RedWorker *worker)
> {
> spice_warning("update timeout");
> @@ -1458,9 +1448,6 @@ static gboolean worker_source_dispatch(GSource *source,
> GSourceFunc callback,
> red_process_cursor(worker, &ring_is_empty);
> red_process_display(worker, &ring_is_empty);
>
> - /* TODO: remove me? that should be handled by watch out condition */
> - red_push(worker);
> -
> return TRUE;
> }
>
More information about the Spice-devel
mailing list