From 5d8878b582b8b68d19ab02adfe32d683d5ea512f Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 4 Sep 2024 17:18:38 +1000 Subject: 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 --- shared/tinyusb/mp_usbd_runtime.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'shared/tinyusb/mp_usbd_runtime.c') diff --git a/shared/tinyusb/mp_usbd_runtime.c b/shared/tinyusb/mp_usbd_runtime.c index fe28a4a727..4955382577 100644 --- a/shared/tinyusb/mp_usbd_runtime.c +++ b/shared/tinyusb/mp_usbd_runtime.c @@ -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 -- cgit v1.2.3