[Spice-devel] [PATCH spice-gtk] agent: avoid use of alloca for sending large msg

Hans de Goede hdegoede at redhat.com
Thu Apr 5 07:38:51 PDT 2012


Hi,

The innerloop is a bit hard to read, but it does the trick, so ACK.

Regards,

Hans


On 04/05/2012 03:35 PM, Marc-André Lureau wrote:
> Instead of allocating unbounded memory and doing extra copy on the
> stack, let's just improve our helper function to send messages in
> various pieces.
>
> See also: https://bugzilla.redhat.com/show_bug.cgi?id=809145
> ---
>   gtk/channel-main.c |   73 +++++++++++++++++++++++++++++++++++++--------------
>   1 files changed, 53 insertions(+), 20 deletions(-)
>
> diff --git a/gtk/channel-main.c b/gtk/channel-main.c
> index 86e6fba..8d0a809 100644
> --- a/gtk/channel-main.c
> +++ b/gtk/channel-main.c
> @@ -771,17 +771,31 @@ static void agent_send_msg_queue(SpiceMainChannel *channel)
>   }
>
>   /* any context: the message is not flushed immediately,
> -   you can wakeup() the channel coroutine or send_msg_queue() */
> -static void agent_msg_queue(SpiceMainChannel *channel, int type, int size, void *data)
> +   you can wakeup() the channel coroutine or send_msg_queue()
> +
> +   expected arguments, pair of data/data_size to send terminated with NULL:
> +   agent_msg_queue_many(main, VD_AGENT_...,
> +&foo, sizeof(Foo),
> +                        data, data_size, NULL);
> +*/
> +G_GNUC_NULL_TERMINATED
> +static void agent_msg_queue_many(SpiceMainChannel *channel, int type, const void *data, ...)
>   {
> +    va_list args;
>       SpiceMainChannelPrivate *c = channel->priv;
>       SpiceMsgOut *out;
>       VDAgentMessage msg;
>       guint8 *payload;
> -    guint32 paysize;
> -    guint8 *d = data;
> +    gsize paysize, s, mins, size = 0;
> +    const guint8 *d;
>
> -    g_assert(VD_AGENT_MAX_DATA_SIZE>  sizeof(VDAgentMessage)); // could be a static compilation check
> +    G_STATIC_ASSERT(VD_AGENT_MAX_DATA_SIZE>  sizeof(VDAgentMessage));
> +
> +    va_start(args, data);
> +    for (d = data; d != NULL; d = va_arg(args, void*)) {
> +        size += va_arg(args, gsize);
> +    }
> +    va_end(args);
>
>       msg.protocol = VD_AGENT_PROTOCOL;
>       msg.type = type;
> @@ -792,21 +806,42 @@ static void agent_msg_queue(SpiceMainChannel *channel, int type, int size, void
>       out = spice_msg_out_new(SPICE_CHANNEL(channel), SPICE_MSGC_MAIN_AGENT_DATA);
>       payload = spice_marshaller_reserve_space(out->marshaller, paysize);
>       memcpy(payload,&msg, sizeof(VDAgentMessage));
> -    memcpy(payload + sizeof(VDAgentMessage), d, paysize - sizeof(VDAgentMessage));
> -    size -= (paysize - sizeof(VDAgentMessage));
> -    d += (paysize - sizeof(VDAgentMessage));
> -    g_queue_push_tail(c->agent_msg_queue, out);
> -
> -    while ((paysize = MIN(VD_AGENT_MAX_DATA_SIZE, size))>  0) {
> -        out = spice_msg_out_new(SPICE_CHANNEL(channel), SPICE_MSGC_MAIN_AGENT_DATA);
> -        payload = spice_marshaller_reserve_space(out->marshaller, paysize);
> -        memcpy(payload, d, paysize);
> +    payload += sizeof(VDAgentMessage);
> +    paysize -= sizeof(VDAgentMessage);
> +    if (paysize == 0) {
>           g_queue_push_tail(c->agent_msg_queue, out);
> -        size -= paysize;
> -        d += paysize;
> +        out = NULL;
> +    }
> +
> +    va_start(args, data);
> +    for (d = data; size>  0; d = va_arg(args, void*)) {
> +        s = va_arg(args, gsize);
> +        while (s>  0) {
> +            if (out == NULL) {
> +                paysize = MIN(VD_AGENT_MAX_DATA_SIZE, size);
> +                out = spice_msg_out_new(SPICE_CHANNEL(channel), SPICE_MSGC_MAIN_AGENT_DATA);
> +                payload = spice_marshaller_reserve_space(out->marshaller, paysize);
> +            }
> +            mins = MIN(paysize, s);
> +            memcpy(payload, d, mins);
> +            d += mins;
> +            payload += mins;
> +            s -= mins;
> +            size -= mins;
> +            paysize -= mins;
> +            if (paysize == 0) {
> +                g_queue_push_tail(c->agent_msg_queue, out);
> +                out = NULL;
> +            }
> +        }
>       }
> +    va_end(args);
> +    g_warn_if_fail(out == NULL);
>   }
>
> +#define agent_msg_queue(Channel, Type, Size, Data) \
> +    agent_msg_queue_many((Channel), (Type), (Data), (Size), NULL)
> +
>   /* any context: the message is not flushed immediately,
>      you can wakeup() the channel coroutine or send_msg_queue() */
>   gboolean spice_main_send_monitor_config(SpiceMainChannel *channel)
> @@ -971,7 +1006,7 @@ static void agent_clipboard_notify(SpiceMainChannel *channel, guint selection,
>       g_return_if_fail(VD_AGENT_HAS_CAPABILITY(c->agent_caps,
>           sizeof(c->agent_caps), VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
>
> -    msgsize = sizeof(VDAgentClipboard) + size;
> +    msgsize = sizeof(VDAgentClipboard);
>       if (HAS_CLIPBOARD_SELECTION(c))
>           msgsize += 4;
>       else if (selection != VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
> @@ -990,9 +1025,7 @@ static void agent_clipboard_notify(SpiceMainChannel *channel, guint selection,
>       }
>
>       cb->type = type;
> -    memcpy(cb->data, data, size);
> -
> -    agent_msg_queue(channel, VD_AGENT_CLIPBOARD, msgsize, msg);
> +    agent_msg_queue_many(channel, VD_AGENT_CLIPBOARD, msg, msgsize, data, size, NULL);
>   }
>
>   /* any context: the message is not flushed immediately,


More information about the Spice-devel mailing list