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 594148 - GSimpleAsyncResult warning
GSimpleAsyncResult warning
Status: RESOLVED FIXED
Product: glib
Classification: Platform
Component: gio
unspecified
Other Linux
: Normal normal
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks:
 
 
Reported: 2009-09-04 15:39 UTC by David Zeuthen (not reading bugmail)
Modified: 2009-09-07 08:27 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description David Zeuthen (not reading bugmail) 2009-09-04 15:39:51 UTC
Hey Alex and Dan,

In the 2.21.x cycle, GSimpleAsyncResult started printing

 g_simple_async_result_complete() called from outside main loop!

in some of my programs using the GIO async stack for D-Bus operations. Let me first explain when this happens and then we can discuss what to do about it.

In both EggDBus [1] and some of the work that this work inspired, the GDBus work [2], the basic primitive is this asynchronous method

 guint        g_dbus_connection_send_dbus_1_message_with_reply
                (GDBusConnection    *connection,
                 DBusMessage        *message,
                 gint                timeout_msec,
                 GCancellable       *cancellable,
                 GAsyncReadyCallback callback,
                 gpointer            user_data);
 
 DBusMessage *g_dbus_connection_send_dbus_1_message_with_reply_finish
                (GDBusConnection *connection,
                 GAsyncResult    *res,
                 GError         **error);

and generated code (from IDL) typically end up calling these methods.

Now, to easily implement synchronous D-Bus calls, the send_dbus_1_message_with_reply() returns an opaque pending call id so the user can call

 void         g_dbus_connection_send_dbus_1_message_block
                (GDBusConnection *connection,
                 guint pending_call_id);

which will block the thread (e.g. not wait in the mainloop). It guarantees that @callback will be invoked before the _send_dbus_1_message_block() function returns (this uses dbus_pending_call_block() internally). This makes it really simple to generate small client proxies - e.g.

 void foo_invoke_bar (Foo                *foo,
                      const gchar        *some_arg_with_signature_s,
                      GCancellable       *cancellable,
                      GAsyncReadyCallback callback,
                      gpointer            user_data)
 {
   ..
 }

 void foo_invoke_bar_finish (Foo             *foo,
                             GArray          *out_some_arg_with_signature_ay,
                             GAsyncResult    *res,
                             GError         **error)
 {
   ..
 }

which just encodes/decodes DBusMessage objects (using a utility methods on the GDBusProxy base-class that the Foo class inherits). Notably, the generated _sync function just calls foo_invoke_bar(), then the _block() method and then foo_invoke_bar_finish() to collect the results. Simple as pie, just like the doctor ordered for generated code.

Now, the problem here is that there may not _even_ be a mainloop available for all this: people should be able to call foo_invoke_bar_sync() from main() and have things work. In this case, however, g_main_current_source() returns NULL and this makes g_simple_async_result_complete() issue a warning...

(Btw, I know that the GDBusConnection code needs to check that g_dbus_connection_send_dbus_1_message_block() is called from the same thread that g_dbus_connection_send_dbus_1_message_with_reply() was called from).

It seems to me, but I'm not 100% sure, that it really isn't right for GSimpleAsyncResult to print "g_simple_async_result_complete() called from outside main loop!" - what is the exact reasoning for this?

Thanks,
David

[1] : http://cgit.freedesktop.org/~david/eggdbus
[2] : http://cgit.freedesktop.org/~david/gdbus-standalone
Comment 1 Dan Winship 2009-09-04 16:12:28 UTC
In theory, this is NOTABUG; GAsyncResult is for doing GMainLoop-based async stuff, and if you're not using a GMainLoop, you shouldn't be using GAsyncResult blah blah blah. But GSimpleAsyncResult is generically useful, so maybe we should be nice.

The warnings (there are two, "called from wrong context" and "called from outside main loop") were added to debug people who were misusing g_main_context_push_thread_default(). In particular, the "called from wrong context" error always means that either the app is trying to use a thread-default context with an object that doesn't support them, or that an object that is trying to support thread-default contexts has a bug.

I don't remember there being a specific reason for the "called from outside main loop" warning, other than that it seemed right, and the code needed to check current_source!=NULL anyway to avoid crashing. If the async_result really is being used for an async op, this case would also definitely count as a bug, but if you're "cheating" and using GSimpleAsyncResult for non-async stuff, then...

I guess we can just remove the "called from outside main loop" warning, but leave the "called from wrong context" one there. OK, Alex?
Comment 2 David Zeuthen (not reading bugmail) 2009-09-04 17:41:15 UTC
(In reply to comment #1)
> In theory, this is NOTABUG; GAsyncResult is for doing GMainLoop-based async
> stuff, and if you're not using a GMainLoop, you shouldn't be using GAsyncResult
> blah blah blah. 

Yeah, I actually agree with you here. FWIW, I'm now changing the GDBus code to avoid using GSimpleAsyncResult for the sync case - e.g. kick out the _block() method and just provide a send_with_reply_sync() method directly. The API is probably better that way.

> But GSimpleAsyncResult is generically useful, so maybe we
> should be nice.

It wouldn't hurt doing this - this bug also exists in the EggDBus code I wrote and currently polkit-1 is using that so the bug exists in e.g. Rawhide and other distros using that code. The longer term plan is to switch polkit-1 away from EggDBus (the dependency is not visible in the API or ABI) but that's going to take a while... I probably could fix EggDBus the same way I'm fixing GDBus but.
Comment 3 Alexander Larsson 2009-09-07 08:23:44 UTC
Well, if you're e.g. calling g_simple_async_result_complete() directly from the worker thread (accidentally, instead of complete_in_idle()) this warning would help you debug this.

However, since there is deployed code using GSimpleAsyncResult this way and since it doesn't seem like it could fix any more subtle issue with the multiple main context case i guess its pretty ok to just remove that check.
Comment 4 Alexander Larsson 2009-09-07 08:27:46 UTC
removed.