glib bindings and memory management

Colin Walters walters at verbum.org
Mon May 2 23:21:47 PDT 2005


Hi,

In the last discussion about what the glib bindings should look like, we
kind of decided to build a single structure out of recursive types, with
the reasoning that we can avoid the "destructor" problem by doing
everything in one malloc block.

However I realized that there are really four closely related but still
separate cases here:

1) Client-side input parameters
   - allocated by client, freed by client (if necessary)
2) Client-side return values
   - allocated by dbus, freed by client
3) Server-side input values
   - allocated by dbus, freed by dbus
4) Server-side return values
   - allocated by client, freed by dbus

(by "dbus" here i mean dbus-glib.so).

Let's take as an example a method like this:

    <method name="Foo">
      <arg type="as" direction="in"/>
      <arg type="as" direction="out"/>
    </method>

On the client end, we need to pass in an array of strings.  Now, the
immediate "obvious" mapping for this is "char **".  But that doesn't
work, we need to know how long the array is.  To solve this I created a
simple structure "DBusGArray" which holds a length member.  I debated
mapping this to GArray but that seemed a bit more heavyweight.  For this
case, it's not really important to dbus; it's just reading the values.

Now, the client also gets a return value of an array of strings.  The
existing code can turn this into a DBusGArray in one malloc block; all
the client has to do is call free() when it's done.  OK.

On the server input end, we have no problem since dbus manages the
memory itself; it can do whatever it wants internally.

The server return value end is where we run into problems, since here
the values are allocated by the client.  How do we free them?  This
problem is related to the issue of how exactly to map the values.  I
basically see two options.  

1) The return value formal parameter is of an opaque "DBusGValue *"
type.  Require the client to use a special API for appending to this
value; e.g.:

gboolean
my_object_foo (MyObject *obj, DBusGArray *array, DBusGValue *ret, GError
**error) 
{
  int i;
  DBusGValueIter valiter;

  dbus_gvalue_open_array (ret, &valiter);
  for (i = 0; i < array->length; i++) 
  {
    char *val = g_strdup_printf ("%d", array->values[i]);
    dbus_gvalue_iter_append_string (&valiter, val);
    g_free (val);
  }
}

2) Map these return values to the GLib types, and have a specific
protocol for deallocation.  For example, we would do this:

gboolean
my_object_foo (MyObject *obj, DBusGArray *array, GArray **ret, GError
**error) 
{
  int i;

  *ret = g_array_new (FALSE, TRUE, sizeof (gchar *));
  for (i = 0; i < array->length; i++) 
  {
    char *val = g_strdup_printf ("%d", array->values[i]);
    g_array_append_val (*ret, val);
  }
}

Note that now we are requiring the dbus library to know that for an
array of strings, it should individually free() each value, and to use
g_array_free (arr, TRUE).   The complication here is variants; for those
we really need the dbus_gvalue_* functions which basically wrap the
message iter API.  I think this second option is nicer though since it
feels more native.

Anyways...thoughts?

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part
Url : http://lists.freedesktop.org/archives/dbus/attachments/20050503/585cd085/attachment.pgp


More information about the dbus mailing list