Optimize reading strings when deserializing gdbus messages

Now that we're directly accessing the memory holding a message blob,
we can access strings directly while reading them. This speeds up
read_string significantly, since we no longer malloc/memcpy/free.
This commit is contained in:
Michael Gorse 2012-11-29 16:51:59 -06:00
parent a5f57bad20
commit fe0b77fea8

View File

@ -66,27 +66,6 @@ struct _GMemoryBuffer
GDataStreamByteOrder byte_order; GDataStreamByteOrder byte_order;
}; };
static gssize
g_memory_buffer_read (GMemoryBuffer *mbuf,
void **buffer,
gsize count,
GError **error)
{
gssize res;
if (((gssize) count) < 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
_("Too large count value passed to %s"), G_STRFUNC);
return -1;
}
res = MIN (count, mbuf->valid_len - mbuf->pos);
*buffer = mbuf->data + mbuf->pos;
mbuf->pos += res;
return res;
}
static guchar static guchar
g_memory_buffer_read_byte (GMemoryBuffer *mbuf, g_memory_buffer_read_byte (GMemoryBuffer *mbuf,
GError **error) GError **error)
@ -1384,28 +1363,17 @@ ensure_input_padding (GMemoryBuffer *buf,
return TRUE; return TRUE;
} }
static gchar * static const gchar *
read_string (GMemoryBuffer *mbuf, read_string (GMemoryBuffer *mbuf,
gsize len, gsize len,
GError **error) GError **error)
{ {
gchar *str; gchar *str;
guchar nul;
GError *local_error;
const gchar *end_valid; const gchar *end_valid;
gssize num_read;
gchar *ptr;
str = g_malloc (len + 1); if (mbuf->pos + len >= mbuf->valid_len || mbuf->pos + len < mbuf->pos)
num_read = g_memory_buffer_read (mbuf,
(void **)&ptr,
len,
error);
if (num_read < 0)
goto fail;
if (num_read < len)
{ {
mbuf->pos = mbuf->valid_len;
/* G_GSIZE_FORMAT doesn't work with gettext, so we use %lu */ /* G_GSIZE_FORMAT doesn't work with gettext, so we use %lu */
g_set_error (error, g_set_error (error,
G_IO_ERROR, G_IO_ERROR,
@ -1415,19 +1383,27 @@ read_string (GMemoryBuffer *mbuf,
"Wanted to read %lu byte but only got %lu", "Wanted to read %lu byte but only got %lu",
(gulong)len), (gulong)len),
(gulong)len, (gulong)len,
(gulong)num_read); (gulong)mbuf->valid_len - mbuf->pos);
goto fail; mbuf->pos = mbuf->valid_len;
return NULL;
} }
memcpy (str, ptr, len); if (mbuf->data[mbuf->pos + len] != '\0')
local_error = NULL;
nul = g_memory_buffer_read_byte (mbuf, &local_error);
if (local_error != NULL)
{ {
g_propagate_error (error, local_error); str = g_strndup (mbuf->data + mbuf->pos, len);
goto fail; g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_ARGUMENT,
_("Expected NUL byte after the string `%s' but found byte %d"),
str, mbuf->data[mbuf->pos + len]);
g_free (str);
mbuf->pos += len + 1;
return NULL;
} }
str[num_read] = '\0';
str = mbuf->data + mbuf->pos;
mbuf->pos += len + 1;
if (!g_utf8_validate (str, -1, &end_valid)) if (!g_utf8_validate (str, -1, &end_valid))
{ {
gint offset; gint offset;
@ -1440,26 +1416,13 @@ read_string (GMemoryBuffer *mbuf,
_("Expected valid UTF-8 string but found invalid bytes at byte offset %d (length of string is %d). " _("Expected valid UTF-8 string but found invalid bytes at byte offset %d (length of string is %d). "
"The valid UTF-8 string up until that point was `%s'"), "The valid UTF-8 string up until that point was `%s'"),
offset, offset,
(gint) num_read, (gint) len,
valid_str); valid_str);
g_free (valid_str); g_free (valid_str);
goto fail; return NULL;
}
if (nul != '\0')
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_ARGUMENT,
_("Expected NUL byte after the string `%s' but found byte %d"),
str, nul);
goto fail;
} }
return str; return str;
fail:
g_free (str);
return NULL;
} }
/* if just_align==TRUE, don't read a value, just align the input stream wrt padding */ /* if just_align==TRUE, don't read a value, just align the input stream wrt padding */
@ -1623,7 +1586,7 @@ parse_value_from_blob (GMemoryBuffer *buf,
if (!just_align) if (!just_align)
{ {
guint32 len; guint32 len;
gchar *v; const gchar *v;
len = g_memory_buffer_read_uint32 (buf, &local_error); len = g_memory_buffer_read_uint32 (buf, &local_error);
if (local_error != NULL) if (local_error != NULL)
goto fail; goto fail;
@ -1631,7 +1594,6 @@ parse_value_from_blob (GMemoryBuffer *buf,
if (v == NULL) if (v == NULL)
goto fail; goto fail;
ret = g_variant_new_string (v); ret = g_variant_new_string (v);
g_free (v);
} }
break; break;
@ -1641,7 +1603,7 @@ parse_value_from_blob (GMemoryBuffer *buf,
if (!just_align) if (!just_align)
{ {
guint32 len; guint32 len;
gchar *v; const gchar *v;
len = g_memory_buffer_read_uint32 (buf, &local_error); len = g_memory_buffer_read_uint32 (buf, &local_error);
if (local_error != NULL) if (local_error != NULL)
goto fail; goto fail;
@ -1655,11 +1617,9 @@ parse_value_from_blob (GMemoryBuffer *buf,
G_IO_ERROR_INVALID_ARGUMENT, G_IO_ERROR_INVALID_ARGUMENT,
_("Parsed value `%s' is not a valid D-Bus object path"), _("Parsed value `%s' is not a valid D-Bus object path"),
v); v);
g_free (v);
goto fail; goto fail;
} }
ret = g_variant_new_object_path (v); ret = g_variant_new_object_path (v);
g_free (v);
} }
break; break;
@ -1667,7 +1627,7 @@ parse_value_from_blob (GMemoryBuffer *buf,
if (!just_align) if (!just_align)
{ {
guchar len; guchar len;
gchar *v; const gchar *v;
len = g_memory_buffer_read_byte (buf, &local_error); len = g_memory_buffer_read_byte (buf, &local_error);
if (local_error != NULL) if (local_error != NULL)
goto fail; goto fail;
@ -1681,11 +1641,9 @@ parse_value_from_blob (GMemoryBuffer *buf,
G_IO_ERROR_INVALID_ARGUMENT, G_IO_ERROR_INVALID_ARGUMENT,
_("Parsed value `%s' is not a valid D-Bus signature"), _("Parsed value `%s' is not a valid D-Bus signature"),
v); v);
g_free (v);
goto fail; goto fail;
} }
ret = g_variant_new_signature (v); ret = g_variant_new_signature (v);
g_free (v);
} }
break; break;
@ -1874,7 +1832,7 @@ parse_value_from_blob (GMemoryBuffer *buf,
if (!just_align) if (!just_align)
{ {
guchar siglen; guchar siglen;
gchar *sig; const gchar *sig;
GVariantType *variant_type; GVariantType *variant_type;
GVariant *value; GVariant *value;
@ -1891,11 +1849,9 @@ parse_value_from_blob (GMemoryBuffer *buf,
G_IO_ERROR_INVALID_ARGUMENT, G_IO_ERROR_INVALID_ARGUMENT,
_("Parsed value `%s' for variant is not a valid D-Bus signature"), _("Parsed value `%s' for variant is not a valid D-Bus signature"),
sig); sig);
g_free (sig);
goto fail; goto fail;
} }
variant_type = g_variant_type_new (sig); variant_type = g_variant_type_new (sig);
g_free (sig);
value = parse_value_from_blob (buf, value = parse_value_from_blob (buf,
variant_type, variant_type,
FALSE, FALSE,