[Spice-devel] [PATCH spice-gtk] agent: avoid use of alloca for sending large msg
Marc-André Lureau
marcandre.lureau at gmail.com
Thu Apr 5 06:35:10 PDT 2012
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,
--
1.7.7.6
More information about the Spice-devel
mailing list