shared/tinyusb: Only run TinyUSB on the main thread if GIL is disabled.

If GIL is disabled then there's threat of a race condition if some other
code specifically requests USB processing (i.e. to unblock stdio), while
a scheduled TinyUSB callback is already running on another thread.

Relies on the change in the parent commit, where scheduler is restricted
to main thread if GIL is disabled.

Fixes #15390 - "TinyUSB callback can't recurse" exceptions on rp2 when
using _thread module and USB serial I/O.

Adds a unit test for stdin functioning correctly in threads (fails on rp2
port without this fix).

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
This commit is contained in:
Angus Gratton
2024-09-04 17:18:38 +10:00
committed by Damien George
parent 52a593cdb1
commit 5d8878b582
2 changed files with 53 additions and 0 deletions

View File

@@ -501,6 +501,15 @@ void mp_usbd_task_callback(mp_sched_node_t *node) {
// Task function can be called manually to force processing of USB events
// (mostly from USB-CDC serial port when blocking.)
void mp_usbd_task(void) {
#if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL
if (!mp_thread_is_main_thread()) {
// Avoid race with the scheduler callback by scheduling TinyUSB to run
// on the main thread.
mp_usbd_schedule_task();
return;
}
#endif
if (in_usbd_task) {
// If this exception triggers, it means a USB callback tried to do
// something that itself became blocked on TinyUSB (most likely: read or