Android event loop is not thread-safe
- Dominant language
- Python
- Stars
- 5.4k
- Forks
- 827
- Avg merge
- 9h 45m
- Merged PRs (30d)
- 58
Description
In https://github.com/beeware/toga/pull/1706, we made Toga use `call_soon_threadsafe` when adding tasks from another thread. However, it doesn't look like the current Android implementation is actually thread-safe.
In the base class in `asyncio.base_events`, the implementations of `call_soon` and `call_soon_threadsafe` are virtually identical. Both of them call `_call_soon`, which is itself thread-safe because all it does is add the task to a deque. The only difference is that `call_soon_threadsafe` then writes something to a pipe to wake up the event loop.
However, the Android event loop overrides `_call_soon` to call `enqueue_android_wakeup_for_delayed_tasks`, which calls `_get_next_delayed_task_wakeup`, which iterates and modifies many data structures in a way that can't possibly be safe to do outside of the event loop's own thread.
The simplest solution I can think of is to move the call of `_get_next_delayed_task_wakeup` into `run_delayed_tasks`, which always runs on the event loop's own thread, and then pass the result as an argument to `enqueue_android_wakeup_for_delayed_tasks`. In the case of `_call_soon`, that argument would always be zero.
* Related: #2179
Contributor guide
Research direction
Start by reading asyncio.base_events and the Android event-loop overrides of _call_soon, run_delayed_tasks, enqueue_android_wakeup_for_delayed_tasks, and _get_next_delayed_task_wakeup. Trace how call_soon_threadsafe behaves from another thread. Done means delayed-task wakeup bookkeeping runs safely on the event-loop thread while both scheduling paths continue to wake the loop correctly.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, python
- Domain
- mobile
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100