Skip to content

asyncio integration with support to await Gio async functions

Benjamin Berg requested to merge benzea/gio-asyncio into main

This adds a simple asyncio event loop integration for GLib that only works on unix. For a comparison with other integrations, see #500 (closed).

I think it works really well:

  • Implements python asyncio await for Gio async results
  • Supports all python features; after all, it is the python standard selector mainloop
  • User can freely choose the GMainContext, setup works for any threads
  • get_event_loop returns a new loop if the thread has a main context
  • main context can be set by creating a loop and using set_event_loop; but only if there is no default one
    • Nested loops are possible, but setup must be done outside of the GLibEventLoopPolicy -> nested loop work theoretically, but asyncio can't deal with it
      • Only registered with GLibEventLoopPolicy if a default thread main context is pushed and t hen get_event_loop is run
      • Mainloop can also run without GLibEventLoopPolicy being aware of it
  • Correctly handles child watches (by using the python watcher; GLib child watches must not be used)

TODO:

  • Add more/better integration points
    • Overwrite SIGINT for the default main context
    • GApplication.run and similar
  • Add tests for GLib async function integration, i.e. test the !158 (closed) part
  • Add tests for nested main loops works, but python prevents it
  • Switch async/finish detection to use glib!3746 API (will require glib >= 2.82)
  • Decouple Awaitable return from our EventLoop (see !189 (eda6c6c3))
  • Windows support? Should be reasonably simple now, but different. See below
    • Check if the IOCP HANDLE can be used with g_source_add_poll (no thread, simpler logic)

On windows, we can't really register the events with GLib properly. But we could:

  • Subclass IocpProactor and have a custom GSource similar to Linux
  • In prepare:
    • If polling thread is running, we are done; just check if there are events ready
    • If polling thread is not running, call IocpProator._poll with 0 timeout directly to assess readyness
    • If not ready, start/poke polling thread
  • In polling thread:
    • call IocpProactor._poll with (almost) infinite timeout
    • when it returns, wakeup main context
    • wait for until being poked again by source
  • In check, just handle timeouts and grab event list
Edited by Benjamin Berg

Merge request reports