GNOME Bugzilla – Bug 787312
Sync methods don't block, and async methods don't invoke callbacks in the thread-default GMainContext
Last modified: 2018-09-24 09:55:08 UTC
Forked from "Synchronous methods get stuck when used in threaded paths": https://bugzilla.gnome.org/show_bug.cgi?id=762496#c1 The use-case for the original complaint was: A GMainLoop-based program that uses asynchronous operations to avoid blocking the main thread. Some of these asynchronous operations are offered by base classes or interfaces, where the implementation comes from a child or implementation class. It is a common pattern to let the base class / interface deal with all the async boilerplate, and have the child / implementation only provide a "simple" synchronous method which is run in a thread. See the attached test case. However, this is a sympton of a more generic problem. Let's take grl_source_resolve as an example. The asynchronous variant uses g_idle_add* to dispatch the callbacks. ie. the callback is run in the NULL or global GMainContext. Instead, the GIO idiom is to use the thread-default GMainContext at the time of invoking the async method. Both GTask and GSimpleAsyncResult use g_main_context_ref_thread_default to track the thread-default context at the time of their construction, and use it to invoke callbacks. This is important because sometimes the synchronous variant of a method is implemented in terms of its asynchronous counterpart by wrapping it in a new thread-default GMainContext. (This sync method might then be used by an application in a worker thread.) All the child async methods in the chain should invoke their callbacks in the thread-default GMainContext. Otherwise, even though the chain was initiated in a thread, they would be invoking their callbacks, and the remainder of the chain, in the global GMainContext, which usually means the main thread. The synchronous variant, grl_source_resolve_sync, is almost like the one in the previous paragraph. Except it doesn't push a fresh new GMainContext before calling its asynchronous counterpart. This means that it is iterating a GMainContext with GSources that are not related to this call, and potentially triggering them. Hence, the sync call isn't really blocking because random unrelated callbacks maybe be invoked while it is running.
Created attachment 359187 [details] Test case: sync variants get stuck in threads
Created attachment 359197 [details] [review] source: Invoke the user's callback in the thread-default GMainContext Here's a proof-of-concept of how I'd change the asynchronous methods. Only compile tested. I haven't actually used it to do anything.
Created attachment 359200 [details] [review] source: Stop random GSources from being triggered during a sync call Similarly untested patch, but for the synchronous variant.
Created attachment 359201 [details] [review] source: Stop random GSources from being triggered during a sync call Sorry, forgot to 'git add' one file.
-- GitLab Migration Automatic Message -- This bug has been migrated to GNOME's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/grilo/issues/122.