[Spice-devel] [PATCH spice-gtk 07/10] channel: do not reenter the mainloop at every iteration

Yonit Halperin yhalperi at redhat.com
Mon Sep 9 13:54:32 PDT 2013


Hi,

I think that iterate_write & iterate_read should be symmetrical: in the 
same way iterate_write handles all outgoing messages, iterate_read 
should flush all incoming messages (i.e., the loop in 
spice_channel_iterate can be moved to iterate_read).

But I'll ack it even if you don't change it :)

Cheers,
Yonit.

On 09/08/2013 02:59 PM, Marc-André Lureau wrote:
> From: Marc-André Lureau <marcandre.lureau at gmail.com>
>
> The current coroutine channel_iterate() creates a GSource for the socket
> reenters the mainloop waiting for IO condition. This is really heavy
> usage of mainloop showing up in system time and user space
> profiling (10% of CPU time spent in mainloop overhead). Instead flush
> all pending input messages before switching context and reentering main
> loop.
> ---
>   gtk/spice-channel.c | 35 +++++++++++++++++------------------
>   1 file changed, 17 insertions(+), 18 deletions(-)
>
> diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
> index 778a90b..9fb3b0c 100644
> --- a/gtk/spice-channel.c
> +++ b/gtk/spice-channel.c
> @@ -2107,35 +2107,34 @@ static gboolean spice_channel_iterate(SpiceChannel *channel)
>       SpiceChannelPrivate *c = channel->priv;
>       GIOCondition ret;
>
> -    do {
> -        if (c->state == SPICE_CHANNEL_STATE_MIGRATING &&
> -            !g_coroutine_condition_wait(&c->coroutine, wait_migration, channel))
> -                CHANNEL_DEBUG(channel, "migration wait cancelled");
> +    if (c->state == SPICE_CHANNEL_STATE_MIGRATING &&
> +        !g_coroutine_condition_wait(&c->coroutine, wait_migration, channel))
> +        CHANNEL_DEBUG(channel, "migration wait cancelled");
>
> -        if (c->has_error) {
> -            CHANNEL_DEBUG(channel, "channel has error, breaking loop");
> -            return FALSE;
> -        }
> -
> -        SPICE_CHANNEL_GET_CLASS(channel)->iterate_write(channel);
> +    if (c->has_error) {
> +        CHANNEL_DEBUG(channel, "channel has error, breaking loop");
> +        return FALSE;
> +    }
>
> -        ret = g_coroutine_socket_wait(&c->coroutine, c->sock,
> -            c->state != SPICE_CHANNEL_STATE_MIGRATING ? G_IO_IN : 0);
> +    /* flush any pending write */
> +    SPICE_CHANNEL_GET_CLASS(channel)->iterate_write(channel);
> +    /* go back to main loop, wait for an event or incoming data */
> +    ret = g_coroutine_socket_wait(&c->coroutine, c->sock, G_IO_IN);
>
> -#ifdef WIN32
> -        /* FIXME: windows gsocket is buggy, it doesn't return correct condition... */
> -        ret = g_socket_condition_check(c->sock, G_IO_IN);
> -#endif
> -    } while (ret == 0); /* ret == 0 means no IO condition, but woken up */
> +    /* treat all incoming data (block on message completion) */
> +    while (!c->has_error && (ret & G_IO_IN)) {
> +        if (c->state == SPICE_CHANNEL_STATE_MIGRATING)
> +            break;
>
> -    if (ret & G_IO_IN) {
>           do
>               SPICE_CHANNEL_GET_CLASS(channel)->iterate_read(channel);
>   #if HAVE_SASL
> +        /* flush the sasl buffer too */
>           while (c->sasl_decoded != NULL);
>   #else
>           while (FALSE);
>   #endif
> +        ret = g_socket_condition_check(c->sock, G_IO_IN | G_IO_ERR | G_IO_HUP);
>       }
>
>       if (c->state > SPICE_CHANNEL_STATE_CONNECTING &&
>



More information about the Spice-devel mailing list