[Vala] Asynchronous construction

57 views
Skip to first unread message

tomw

unread,
Mar 27, 2012, 5:44:00 AM3/27/12
to vala...@gnome.org
Hi,
trying to make the gfreenect [1] library work with Vala and in
particular to deal with the missing asynchronous constructor support I
was running into some issues. The vapi [2] is generated from GIR.

The corresponding code in C is pretty straight forward and would
look like this:

static void on_new_kinect_device ( GObject *obj,
GAsyncResult *res,
gpointer user_data)
{
kinect = gfreenect_device_new_finish (res, &error);
if (kinect == NULL)
{
g_debug ("Failed to created kinect device: %s", error->message);
g_error_free (error);
clutter_main_quit ();
return;
}

g_debug ("Kinect device created!");


int main (int argc, char *argv[])
{
gfreenect_device_new (0,
GFREENECT_SUBDEVICE_CAMERA,
NULL,
on_new_kinect_device,
NULL);
clutter_main ();

return 0;
}

Trying to implement that in Vala, I took the approach below.
It seems however, that the init_async does not work. Looking at the
generated C-Code it looks like the g_async_initable_init_finish method
is called right after init_async an not with in the callback as expected.
As a result the code is crashing in the underlying libusb due to
incorrect initialization.

What am I missing here? Any idea how to solve the issue.

thanks and sorry for the lengthy post,

--tomw

---------------------------------------------------------

using GLib;
using GFreenect;

public class Main : Object
{

public GFreenect.Device device;
public Cancellable cancellable;

public Main () {
Cancellable cancellable = new Cancellable ();

}

public async void run (out Device dev) {
debug ("Starting");
Device device = (Device) GLib.Object.@new (
typeof (Device),
"index", 0,
"subdevices", Subdevice.CAMERA
);
debug ("Device created");
Idle.add (run.callback);
try {
debug ("Trying to run init_async");
bool re = yield device.init_async (Priority.DEFAULT, cancellable);
if (re) {
debug ("Result = OK");
} else {
debug ("Result = FAILED");
}
} catch (Error e) {
debug ("Error initalizing device : %s", e.message);
}
}

public void callback (Main? source, GLib.AsyncResult? res, void* user_data) {
debug ("Entering Callback");
Device dev;
if (res != null) {
source.run.end (res, out dev);
debug ("Callback called - Device created");
try {
Device kinect = new dev.finish(res);
} catch (Error e) {
debug ("Error finalizing device : %s", e.message);
}
} else {
debug ("No result delivered");
}
}

static int main (string[] args) {
var loop = new MainLoop ();
var app = new Main ();
app.run.begin ((AsyncReadyCallback)callback);
loop.run ();

return 0;
}

}


[1] https://gitorious.org/gfreenect
[2] http://pastebin.com/xdXKCmWR

_______________________________________________
vala-list mailing list
vala...@gnome.org
http://mail.gnome.org/mailman/listinfo/vala-list

Jens Georg

unread,
Mar 27, 2012, 5:59:44 AM3/27/12
to to...@ubilix.com, vala...@gnome.org

> Hi,

[Freenect C init sample ]

^^ No need for this since you're using yield in the function. Might
actually be harmful, causing a race between the init_async you call and
the one Vala calls implicitly.

> try {
> debug ("Trying to run init_async");
> bool re = yield device.init_async (Priority.DEFAULT, cancellable);

^^ this yield returns to main loop and once init_async calls its
call-back will call init_finish for you. So after this line the device
is initialized.

> if (re) {
> debug ("Result = OK");
> } else {
> debug ("Result = FAILED");
> }
> } catch (Error e) {
> debug ("Error initalizing device : %s", e.message);
> }
> }
>
> public void callback (Main? source, GLib.AsyncResult? res, void* user_data) {
> debug ("Entering Callback");
> Device dev;
> if (res != null) {
> source.run.end (res, out dev);
> debug ("Callback called - Device created");
> try {
> Device kinect = new dev.finish(res);

^^ And here you're basically trying to create another device.

> } catch (Error e) {
> debug ("Error finalizing device : %s", e.message);
> }
> } else {
> debug ("No result delivered");
> }
> }

I would do it like this:
using GLib;
using GFreenect;

public class Main : Object
{

public GFreenect.Device device;
public Cancellable cancellable;

public Main () {
Cancellable cancellable = new Cancellable ();

}

public async void run () {


debug ("Starting");
Device device = (Device) GLib.Object.@new (
typeof (Device),
"index", 0,
"subdevices", Subdevice.CAMERA
);
debug ("Device created");

try {
debug ("Trying to run init_async");
bool re = yield device.init_async (Priority.DEFAULT, cancellable);

// start using the device
} catch (Error e) {
// re will always be true in the try block if you always get an error
// when it's false, because you end up here anyway.


debug ("Error initalizing device : %s", e.message);
}
}

static int main (string[] args) {


var loop = new MainLoop ();
var app = new Main ();

app.run.begin ();
loop.run ();

return 0;

tomw

unread,
Mar 27, 2012, 6:24:11 AM3/27/12
to Jens Georg, vala...@gnome.org
On Di, 2012-03-27 at 11:59 +0200, Jens Georg wrote:

> > try {
> > debug ("Trying to run init_async");
> > bool re = yield device.init_async (Priority.DEFAULT, cancellable);
>
> ^^ this yield returns to main loop and once init_async calls its
> call-back will call init_finish for you. So after this line the device
> is initialized.

Thanks,

I'm afraid that the statement above is just initializing a new device
instance, which (according to gfreenect) can only be used after
gfreenect_device_new_finish () is called like in the C example. This is
why I was trying to create a finished instance in the callback. As the
code is still crashing in libusb - Is there a way to get the callback
called rather than the implicit init_finish being called from
init_async?

--tomw

Jens Georg

unread,
Mar 27, 2012, 7:13:40 AM3/27/12
to to...@ubilix.com, vala...@gnome.org
On Di, 2012-03-27 at 12:24 +0200, tomw wrote:
> On Di, 2012-03-27 at 11:59 +0200, Jens Georg wrote:
>
> > > try {
> > > debug ("Trying to run init_async");
> > > bool re = yield device.init_async (Priority.DEFAULT, cancellable);
> >
> > ^^ this yield returns to main loop and once init_async calls its
> > call-back will call init_finish for you. So after this line the device
> > is initialized.
>
> Thanks,
>
> I'm afraid that the statement above is just initializing a new device
> instance, which (according to gfreenect) can only be used after
> gfreenect_device_new_finish () is called like in the C example. This is
> why I was trying to create a finished instance in the callback. As the
> code is still crashing in libusb - Is there a way to get the callback
> called rather than the implicit init_finish being called from
> init_async?

gfreenect_device_new_finished is just calling _async_initable_new_finish
which calls async_initable_finish, same for _device_new. Removing the
subdevices property stops the crashing here. looking at the gfreenect
code that isn't used at all:
https://github.com/elima/GFreenect/blob/master/gfreenect/gfreenect-device.c#L1150

tomw

unread,
Mar 27, 2012, 7:31:14 AM3/27/12
to Jens Georg, vala...@gnome.org
> gfreenect_device_new_finished is just calling _async_initable_new_finish
> which calls async_initable_finish, same for _device_new. Removing the
> subdevices property stops the crashing here. looking at the gfreenect
> code that isn't used at all:
> https://github.com/elima/GFreenect/blob/master/gfreenect/gfreenect-device.c#L1150
>
Thanks, indeed. It works. The reason is kind of strange though as this
parameter is used in C and Python examples. I was suspecting bindings
and a lot of other things but I would not think of a parameter like
this...

many thanks,

--tomw

Reply all
Reply to author
Forward
0 new messages