[Libguestfs] GObject bindings overview
Richard W.M. Jones
rjones at redhat.com
Fri Jan 20 13:44:10 UTC 2012
On Fri, Jan 20, 2012 at 12:07:47PM +0000, Matthew Booth wrote:
> I've summarised how the GObject bindings work below, which should
> hopefully help reviewing the generator/generated code.
>
> There are a couple of points in here I'm still not 100% happy with.
> Specifically the handling of FBuffer and the Cancellable flag. Both
> are explained below. I'm interested in suggestions.
>
> Return values:
> **************
>
> All functions which can return an error have as their final argument
> a GError **. GI maps this to the appropriate error mechanism for
> each target language.
>
> RErr returns a gboolean, true = success, false = failure.
> The following types return the value from libguestfs unchanged:
> RInt
> RInt64
> RBool
> RConstString (transfer none): gobject doesn't manage returned memory
> RConstOptString (transfer none). Methods don't return an error (no
> GError**)
> RString
> RStringList
>
> RHashtable is converted to a GHashTable. The keys and values from
> libguestfs are inserted directly into the GHashTable without
> copying. The top level array returned by libguestfs is freed.
It could be useful to run the gobject tests under valgrind.
See tests/extra/Makefile.am
> RStruct is converted to GObject boxed type for the target struct. It
> returns a copy of the struct, which is copied field by field. Memory
> for the returned struct is allocated using glib's slice allocator.
> The original struct is freed with guestfs_free_<struct>().
>
> RStructList is converted as an array of structs, which are
> individually converted the same way as RStruct, i.e. everything is
> copied. The returned array is a newly allocated NULL-terminated
> array. The originally returned value is freed with
> guestfs_free_<struct>_list().
>
> RBufferOut is returned as a guint8 array, whose length is specified
> by a size_r field. GObject uses both these fields to construct a
> single array object where language bindings allow. The value
> returned by RBufferOut is not copied.
>
> Structs:
> ********
>
> A parallel struct is created for each libguestfs struct type. A
> boxed type is created for each parallel struct. It's field types are
> all mapped trivially to gobject basic types (e.g. gchar *, gint32)
> except FBuffer. FBuffer is mapped as:
>
> guint8 *<field>
> guint32 <field>_size
>
> Unfortunately I can see no way to attach annotation to these fields,
> so the bindings do not appreciate that these fields are related. I'm
> not happy with this at all, so I may try manual tweaking of the .gir
> to see if we can turn these into a single returned array where
> possible.
>
> Required arguments:
> *******************
>
> Required arguments to methods are all mapped trivially to gobject
> basic types. They are all passed directly to libguestfs. StringList
> and DeviceList both remain null-terminated arrays. BufferIn has
> separate array and length components, which are combined into a
> single array using annotations where language bindings permit.
>
> Optional arguments:
> *******************
>
> Optional arguments are implemented as a separate gobject whose name
> is is Guestfs<camel api name>. This gobject has defined properties
> for each optional argument accepted by the api. All properties are
> initially undefined. Property types are mapped as:
>
> OBool -> GuestfsTristate
> OInt, OInt64 -> gint/gint64. -1 is used internally as a magic
> value to represent undefined.
> OString -> gchar *. NULL represents undefined.
>
> GuestfsTristate is a new boxed enum type with values FALSE, TRUE and
> UNSET. In the javascript bindings at least, passing in 'true' or
> 'false' here works as expected. To set the UNSET value, you have to
> explicitly use GuestfsTristate.UNSET.
>
> OInt and OInt64 have a similar problem to boolean, in that there's
> no way to represent unset in the fundamental type. The -1 =
> undefined scheme is an internal detail and need not be part of the
> API. I did create a patch to make the undefined number explicit for
> each optional argument which required it. However I decided to hold
> off on it until we actually create an api where this would be a
> problem, as it makes the api definition in the generator slightly
> uglier and more complex.
>
> Where no optional arguments are required, the user can pass in the
> binding language's equivalent of NULL. GObject has a placeholder for
> default values, but there are not yet implemented. When they are, we
> can define the default value of optargs to be null, meaning they can
> be entirely omitted when not required.
>
> Cancellation:
> *************
>
> Certain apis are cancellable. These all take a GCancellable as the
> final argument before GError **. This can be passed NULL if
> cancellation is not required. While I have written cancellation, I
> have not yet tested it *at all* other than it compiles and works
> correctly when NULL is passed in.
>
> We recently made Cancellable an explicit flag whereas before it was
> implicit if the api had a FileIn or FileOut argument. This means it
> is now possible to break the GObject api without breaking the C api
> with the addition of a Cancellable flag. What potential solutions
> are there to this problem? I can see:
>
> • Live with breaking the GObject api if it ever comes up.
> • Never add Cancellable to an existing api.
> • Automatically add a GCancellable argument to all GObject apis,
> just in case.
The right way is to add a check to generator_checks.ml which
ensures that presence of FileIn/FileOut === Cancellable flag
in flags.
> Events API
> **********
>
> The libguestfs events API is not yet bound. I'll add this at a later stage.
>
> Matt
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
virt-p2v converts physical machines to virtual machines. Boot with a
live CD or over the network (PXE) and turn machines into Xen guests.
http://et.redhat.com/~rjones/virt-p2v
More information about the Libguestfs
mailing list