After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 602417 - Document lifecycles of GSimpleAsyncResult and friends
Document lifecycles of GSimpleAsyncResult and friends
Status: VERIFIED FIXED
Product: glib
Classification: Platform
Component: gio
2.22.x
Other Linux
: Normal normal
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks:
 
 
Reported: 2009-11-19 15:36 UTC by Will Thompson
Modified: 2010-09-27 15:59 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Give an example of using GSimpleAsyncResult (3.89 KB, patch)
2009-11-19 17:05 UTC, Will Thompson
needs-work Details | Review
Apply English pedantry to GAsyncInitable's docs (5.57 KB, patch)
2009-11-20 13:10 UTC, Will Thompson
committed Details | Review
Document a simple implementation of GAsyncInitable (3.84 KB, patch)
2009-11-20 13:10 UTC, Will Thompson
none Details | Review
g_simple_async_result_is_valid: allow tag to be NULL (2.07 KB, patch)
2009-12-30 00:36 UTC, Will Thompson
none Details | Review
g_simple_async_result_is_valid: allow tag to be NULL (2.02 KB, patch)
2009-12-30 00:40 UTC, Will Thompson
none Details | Review
Give an example of using GSimpleAsyncResult (4.30 KB, patch)
2009-12-30 00:40 UTC, Will Thompson
none Details | Review
Document that _complete() et al. ref the GSimpleAsyncResult (1.82 KB, patch)
2009-12-30 00:40 UTC, Will Thompson
committed Details | Review
Document that _finish() may be called at most once. (2.36 KB, patch)
2009-12-30 00:40 UTC, Will Thompson
committed Details | Review
Correct a typo in GAsyncResult's documentation (1011 bytes, patch)
2009-12-30 00:40 UTC, Will Thompson
committed Details | Review
[PATCH 2/3] Give an example of using GSimpleAsyncResult (4.70 KB, patch)
2010-02-19 16:12 UTC, Will Thompson
none Details | Review
Document a simple implementation of GAsyncInitable (3.60 KB, patch)
2010-02-19 16:14 UTC, Will Thompson
none Details | Review
Allow stored tag to be NULL in GSimpleAsyncResult (1020 bytes, patch)
2010-09-27 15:59 UTC, Nicolas Dufresne (ndufresne)
none Details | Review

Description Will Thompson 2009-11-19 15:36:08 UTC
I just noticed that some code I'm writing using GAsync* is leaking a bunch of stuff. Turns out that I'm leaking every GSimpleAsyncResult, mainly because I wasn't sure where I was meant to be discarding my reference. I've discovered by asking around that I can unref it and throw it away after calling _complete() or _complete_in_idle() and the right thing will happen.

It would be useful if the preamble to GSimpleAsyncResult gave an example of the typical ways one implements foo_async and foo_finish using it. Similarly, I'm still a little unsure about who owns which references when I implement GAsyncInitable, so a known-good example of implementing that for a simple object would be nice.
Comment 1 Will Thompson 2009-11-19 17:05:44 UTC
Created attachment 148131 [details] [review]
Give an example of using GSimpleAsyncResult

Here's a first cut at a GSAR example.
Comment 2 Will Thompson 2009-11-20 13:10:01 UTC
Created attachment 148172 [details] [review]
Apply English pedantry to GAsyncInitable's docs

• "asynchronous" was misspelled as "asyncronous" in various places;
• punctuation was missing;
• g_async_initable_new_async() had a stray "and";
• references to g_async_initable_new_finish() were missing a "the".
Comment 3 Will Thompson 2009-11-20 13:10:04 UTC
Created attachment 148173 [details] [review]
Document a simple implementation of GAsyncInitable
Comment 4 David Zeuthen (not reading bugmail) 2009-11-20 14:05:36 UTC
Review of attachment 148173 [details] [review]:

::: gio/gasyncinitable.c
@@ +69,3 @@
+ *
+ *       if (self->priv->success)
+ *         g_simple_async_result_set_op_res_gboolean (simple, TRUE);

I don't think you need to set a boolean here - we always want to set an error on non-success. So your finish function should just do

 if (g_simple_async_result_propagate_error (simple, error))
   return FALSE;

 return TRUE;
Comment 5 David Zeuthen (not reading bugmail) 2009-11-20 14:11:37 UTC
Review of attachment 148131 [details] [review]:

::: gio/gsimpleasyncresult.c
@@ +153,3 @@
+ *                                            BAKER_ERROR_TOO_SMALL,
+ *                                            "%ucm radius cakes are silly",
+ *                                            radius);

There's a problem with g_simple_async_report_error_in_idle() (and other functions) insofar that it doesn't allow you to set the tag.

(I think _report_error_in_idle(), _report_gerror_in_idle() and _new_error() should probably be deprecated?).

Suggest to create the GSimpleAsyncResult up-front and use g_simple_async_result_set_error() instead.
Comment 6 Allison Karlitskaya (desrt) 2009-11-20 15:44:54 UTC
Review of attachment 148131 [details] [review]:

It wouldn't hurt to add notes to the _complete() type calls that they take a reference to the result for as long as is needed to complete the call.

Similar notes would be nice for the functions that take a GError*.

::: gio/gsimpleasyncresult.c
@@ +129,3 @@
+ *   else
+ *     g_simple_async_result_set_op_res_gpointer (result,
+ *                                                g_object_ref (cake),

you should note at the top of baked_cb that the callback is not given its own reference to 'cake' and that cake would normally be destroyed after baked_cb returned.

@@ +153,3 @@
+ *                                            BAKER_ERROR_TOO_SMALL,
+ *                                            "%ucm radius cakes are silly",
+ *                                            radius);

I've always been slightly annoyed by this problem.

I tollerate it, though, because I really enjoy the convenience of using these functions (and I think that good example code should make use of them).

Maybe we could change g_simple_async_result_is_valid() to always pass if the source tag is NULL.

@@ +166,3 @@
+ *     {
+ *       g_simple_async_result_set_op_res_gpointer (simple,
+ *                                                  g_object_ref (cake),

this time you're definitely leaking the cake (assuming the cache returns a reference -- which really, it ought to).

either pass 'cake' directly in, with a note that you're "transfering your reference", or better: g_object_unref(cake) before you return.

@@ +184,3 @@
+ *   Cake               *cake;
+ *
+ *   if (!g_simple_async_result_propagate_error (simple, error))

logic here is backwards.  this function returns TRUE if there is an error.

@@ +188,3 @@
+ *
+ *   g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ *                                                         G_OBJECT (self),

you should move this call all the way up to the top -- even before your G_SIMPLE_ASYNC_RESULT() cast.  part of the purpose of this function is to check that the 'result' is a valid GSimpleAsyncResult, so you should do it before you do anything under that assumption.
Comment 7 Allison Karlitskaya (desrt) 2009-11-20 15:50:25 UTC
Review of attachment 148173 [details] [review]:

i don't feel comfortable making more detailed comments on this patch because i don't fully understand how this stuff works myself :)

::: gio/gasyncinitable.c
@@ +69,3 @@
+ *
+ *       if (self->priv->success)
+ *         g_simple_async_result_set_op_res_gboolean (simple, TRUE);

it's true.  conceptually, this C prototype:

gboolean do_foo (..., GError **error);

is equivalent to this higher-level language declaration:

void do_foo (...) throws GLib.Error;

so really, you're not returning a bool -- you're returning nothing.
Comment 8 Alexander Larsson 2009-11-26 14:28:17 UTC
Review of attachment 148131 [details] [review]:

::: gio/gsimpleasyncresult.c
@@ +132,3 @@
+ *                                                g_object_unref);
+ *
+ *   g_simple_async_result_complete (result);

Calling g_simple_async_result_complete() here is correct if baked_cb is called as a callback from the mainloop, which is most likely. However, if its not you need to call complete_from_idle(), which would be nice to point out.

@@ +153,3 @@
+ *                                            BAKER_ERROR_TOO_SMALL,
+ *                                            "%ucm radius cakes are silly",
+ *                                            radius);

I don't agree. These functions are very convenient, and its a standard pattern in case where you're implementing a virtual function like GFile or GInputStream that the _finish() function handles the error case so that all implementations don't have to do that. This means it would not work to set the tag.

@@ +193,3 @@
+ *
+ *   cake = CAKE (g_simple_async_result_get_op_res_gpointer (simple));
+ *   return g_object_ref (cake);

This is all correct and stuff, but it might be nice to have a more wider description on the exact requirements of the finish function.
First of all, its only valid for it to be called once, so it is allowed to "steal" the object from the async result instead of returning a copy/ref. This is useful if the constructed object isn't refcounted as that allows you to avoid a copy.

Its also allowed to *not* call the finish function from the callback. So, implementations must handle this by freeing the created objects when the async result is freed.

Its also allowed to ref the async result from the callback and call the finish function later.
Comment 9 Alexander Larsson 2009-11-26 14:35:43 UTC
Review of attachment 148173 [details] [review]:

I think this example is a bit contrived, with construction state stored in the object and whatnot.
A better example would be something that does a single async operation in the initialization, like for example:
http://cgit.freedesktop.org/~david/gdbus-standalone/tree/gdbus/gdbusproxy.c
Comment 10 Will Thompson 2009-12-30 00:00:00 UTC
(In reply to comment #9)
> A better example would be something that does a single async operation in the
> initialization, like for example:
> http://cgit.freedesktop.org/~david/gdbus-standalone/tree/gdbus/gdbusproxy.c

Well, that code doesn't implement g_async_initable_init_async() correctly. :-) According to the documentation, it must be idempotent, but if you init a GDBusProxy twice it will call GetAll() twice and leak one hash table of properties.
Comment 11 Will Thompson 2009-12-30 00:36:02 UTC
Created attachment 150558 [details] [review]
g_simple_async_result_is_valid: allow tag to be NULL

Because g_simple_async_report_[g]error_in_idle() don't take a source tag
parameter, code that uses them can't currently use
g_simple_async_result_is_valid() (at least, not for the error case).
So, let's make g_simple_async_result_is_valid() pass if the tag is
NULL.
Comment 12 Will Thompson 2009-12-30 00:36:58 UTC
Comment on attachment 150558 [details] [review]
g_simple_async_result_is_valid: allow tag to be NULL

(sorry, git bz tricked me, but i hit ^C too late)
Comment 13 Will Thompson 2009-12-30 00:40:00 UTC
Created attachment 150559 [details] [review]
g_simple_async_result_is_valid: allow tag to be NULL

Because g_simple_async_report_[g]error_in_idle() don't take a source tag
parameter, code that uses them can't currently use
g_simple_async_result_is_valid() (at least, not for the error case).
So, let's make g_simple_async_result_is_valid() pass if the tag is
NULL.
Comment 14 Will Thompson 2009-12-30 00:40:05 UTC
Created attachment 150560 [details] [review]
Give an example of using GSimpleAsyncResult
Comment 15 Will Thompson 2009-12-30 00:40:10 UTC
Created attachment 150561 [details] [review]
Document that _complete() et al. ref the GSimpleAsyncResult
Comment 16 Will Thompson 2009-12-30 00:40:14 UTC
Created attachment 150562 [details] [review]
Document that _finish() may be called at most once.

In addition, rephrase the relevant paragraphs to make them a bit
clearer.
Comment 17 Will Thompson 2009-12-30 00:40:18 UTC
Created attachment 150563 [details] [review]
Correct a typo in GAsyncResult's documentation
Comment 18 Will Thompson 2010-02-19 16:12:35 UTC
Created attachment 154218 [details] [review]
[PATCH 2/3] Give an example of using GSimpleAsyncResult

This updated patch includes a note about why baked_cb() can use _complete(), and when you should instead use _complete_in_idle().
Comment 19 Will Thompson 2010-02-19 16:14:10 UTC
Created attachment 154219 [details] [review]
Document a simple implementation of GAsyncInitable

An updated version which addresses the comments about not needing to set a boolean on the GSimpleAsyncResult.
Comment 20 Will Thompson 2010-02-19 16:16:47 UTC
The outstanding three patches are visible at http://git.collabora.co.uk/?p=user/wjt/glib;a=shortlog;h=refs/heads/document-async if you're more into that kind of thing. The first example depends on the patch to make _is_valid() accept NULL tags; the second example is stand-alone.

I haven't changed the example to chain down to another async operation; I could do that, but I don't think it would necessarily make the example any clearer.
Comment 21 Matthias Clasen 2010-08-14 03:36:31 UTC
These should be all committed now.Thanks!
Comment 22 Will Thompson 2010-08-14 09:57:49 UTC
Awesome, thanks. :)
Comment 23 Nicolas Dufresne (ndufresne) 2010-09-27 15:49:28 UTC
(In reply to comment #13)
> Created an attachment (id=150559) [details] [review]
> g_simple_async_result_is_valid: allow tag to be NULL
> 
> Because g_simple_async_report_[g]error_in_idle() don't take a source tag
> parameter, code that uses them can't currently use
> g_simple_async_result_is_valid() (at least, not for the error case).
> So, let's make g_simple_async_result_is_valid() pass if the tag is
> NULL.

As discuss today with Will, this patch does not do 100% what he expected. The current patch let you disable tag checking by passing NULL to the tag parameter. But when using g_simple_async_report_* it's the tag inside the GSimpleAsyncResult that is NULL. Which mean, to achieve the initial goal we also need to disable tag checking if the result does not holds a source_tag (e.g. when you are using g_simple_async_report_*). I'll post a patch in few minutes that enable this.
Comment 24 Nicolas Dufresne (ndufresne) 2010-09-27 15:59:12 UTC
Created attachment 171219 [details] [review]
Allow stored tag to be NULL in GSimpleAsyncResult

Allow stored tag to be NULL in GSimpleAsyncResult
    
    This allow using g_simple_async_report_(error|gerror)_in_idle() with
    g_simple_async_result_is_valid() giving a non-NULL source tag. With
    this change, _is_valid() will ignore the source tag if the GSimpleAsyncResult
    was created without one.