Browse Source
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>pull/15448/head
Angus Gratton
2 months ago
committed by
Damien George
2 changed files with 53 additions and 0 deletions
@ -0,0 +1,44 @@ |
|||
# Test that having multiple threads block on stdin doesn't cause any issues. |
|||
# |
|||
# The test doesn't expect any input on stdin. |
|||
# |
|||
# This is a regression test for https://github.com/micropython/micropython/issues/15230 |
|||
# on rp2, but doubles as a general property to test across all ports. |
|||
import sys |
|||
import _thread |
|||
|
|||
try: |
|||
import select |
|||
except ImportError: |
|||
print("SKIP") |
|||
raise SystemExit |
|||
|
|||
|
|||
class StdinWaiter: |
|||
def __init__(self): |
|||
self._done = False |
|||
|
|||
def wait_stdin(self, timeout_ms): |
|||
poller = select.poll() |
|||
poller.register(sys.stdin, select.POLLIN) |
|||
poller.poll(timeout_ms) |
|||
# Ignoring the poll result as we don't expect any input |
|||
self._done = True |
|||
|
|||
def is_done(self): |
|||
return self._done |
|||
|
|||
|
|||
thread_waiter = StdinWaiter() |
|||
_thread.start_new_thread(thread_waiter.wait_stdin, (1000,)) |
|||
StdinWaiter().wait_stdin(1000) |
|||
|
|||
# Spinning here is mostly not necessary but there is some inconsistency waking |
|||
# the two threads, especially on CPython CI runners where the thread may not |
|||
# have run yet. The actual delay is <20ms but spinning here instead of |
|||
# sleep(0.1) means the test can run on MP builds without float support. |
|||
while not thread_waiter.is_done(): |
|||
pass |
|||
|
|||
# The background thread should have completed its wait by now. |
|||
print(thread_waiter.is_done()) |
Loading…
Reference in new issue