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 _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://www.redhat.com/mailman/listinfo/libguestfs