GNOME Bugzilla – Bug 517137
Need async operations with a non-default main context
Last modified: 2009-06-19 21:24:28 UTC
Hi, GIO currently needs a main loop running for the default main context for every async operation as the callbacks at least are made from this main context. It would be nice if there was a _async_with_context() function for every async function that allows one to choose a non-default main context for this. Another possibility would be async functions that simply call the callbacks from another thread instead of relying on a main loop in some main context. This would also solve bug #517071, the reasons why such async operations are needed are listed in that bug too ;)
This is also extremely important for file monitors. Dispatching an event in another main context and/or in a dedicated thread (which could be running its own mainloop or simply looping directly) would be nice features.
I think having a main context argument in all operations, or duplicating each operation so that that is possible is a bad idea. I initially had this, but it severely bloats the API in *all* callers, for something that is extremely rare in use. I think a better idea would be some way to set the default main context to use for the current thread and then use that. Its a chunk of work getting all the async implementations to handle multiple main context though. The original code that did this severely complicated the dbus handling in gvfs for instance.
Only setting the default main context for the current thread is not enough in some cases but could work with some additional effort I guess.
I don't see how that could not be enough, as you can easily create the _async_with_context() wrapper for any async operation by setting the current threads main context, calling the normal async op, then resetting it. Can you describe what you're unable to do with this kind of solution?
As long as the set_default_context() thing was GIO-specific I agree with it for exactly the use you describe above -- using it to temporarily override the main context used by user-facing GIO API. We were talking on IRC about all the problems that would be caused if you were able to override the default context used by glib... Consider how many libraries do things like naïvely scheduling idle handlers as a way to get code back to the mainloop. These libraries would explode if suddenly the idle handlers started running in a different context. I guess, by the way, that the best way to do this would be as a sort of per-thread stack. That way you can write little wrappers like this: gio_do_stuff_with_context (gctx *ctx) { gio_push_default_context (ctx); gio_do_stuff(); gio_pop_default_context (); } That way, regardless of what context overrides you have at entry to this function, you know that you don't get strange side-effects.
(In reply to comment #5) > I guess, by the way, that the best way to do this would be as a sort of > per-thread stack. That way you can write little wrappers like this: > > gio_do_stuff_with_context (gctx *ctx) > { > gio_push_default_context (ctx); > gio_do_stuff(); > gio_pop_default_context (); > } Since this is happening in a single function, no need for a separate stack: gio_do_stuff_with_context (gctx *ctx) { gctx *old_ctx = gio_get_default_context (); gio_set_default_context (ctx); gio_do_stuff(); gio_set_default_context (old_ctx); }
ah... yes. we already have a stack. let's use it. good call :)
There might be cases where it's not a single function though... and having the push/pop mechanism isn't too hard either. If we have that I guess everything is possible ;)
Has anyone started working on this yet? (e.g. as part of gnio maybe?) Any chance of getting this into GLib 2.20?
No and no.
Summary from IRC discussion about this today: * will add some trivial functions to gio to manipulate the context stack * base glib functions like g_idle_ and g_timeout_ will not be affected * certain interfaces/classes will be advertised as "supporting alternate main contexts" by way of the new functions (ie: GInputStream, GOutputStream, etc) * these classes/interfaces will have a new field added to their iface/vtable * this new field will be set non-NULL by an implementation to indicate that it supports alternate main contexts * the interface code (ie: g_input_stream_read_async) will check the vtable to ensure that the value is non-NULL if a non-default main context was set by the caller. a g_critical will be thrown in the case that the user set a alternate context and the implementation is not marked as being able to support that. patches forthcoming
I don't think throwing a g_critical is the right approach, as exactly what i/o implementation gets used could often be a runtime issue. I'd rather it just return an error. (possibly logging something with e.g. g_warning)
*** This bug has been marked as a duplicate of 579984 ***