uos.dupterm() behavior in underspecified, implementations broken
While not directly related to HW API, https://github.com/micropython/micropython/wiki/Hardware-API#os-module-additions specifies os.dupterm(), used for:
os.dupterm([stream_obj]) get or set duplication of controlling terminal, so that REPL can be redirected to UART or other (note: could allow to duplicate to multiple stream objs but that's arguably overkill and could anyway be done in Python by making a stream multiplexer)
Unfortunately, this description is not clear/detailed enough, or alternatively, current implementations of it in stmhal and cc3200 ports are not general or just broken. First of all, it should be made clear if the talk is about duplicating "controlling terminal", or replacing it. If there's talk about duplicating, then there should be immediate talk about non-blocking streams. Otherwise this line https://github.com/micropython/micropython/blob/master/cc3200/hal/cc3200_hal.c#L187 will simply hang the entire REPL, as it will wait until a character is available on that particular stream, ignoring all other input sources.
And then if there's requirement to non-blocking streams, it should be kept in mind that all other REPL sources should be non-blocking too, otherwise standard source can block custom installed one. But requirement of non-blocking sources is merely a minimal condition to get it all working, but working quite inefficiently and requiring weird workaround to not make it burn CPU cycles (and a battery of battery-powered device), e.g. https://github.com/micropython/micropython/blob/master/cc3200/hal/cc3200_hal.c#L196. So, next step is making requirement that REPL sources are pollable, and actually poll them.
That's quite a bunch of requirements to get it working in the general case, sure.
rp2: Can't send KeyboardInterrupt with os.dupterm()
Port, board and/or hardware
rp2
MicroPython version
MicroPython v1.25.0 on 2025-04-15; Raspberry Pi Pico 2 W with RP2350
Reproduction
Call os.dupterm() with UART or other compatible stream object:
from machine import UART
import os
os.dupterm(UART(0), 0)
Run some code:
import time
i = 0
while True:
print(i)
i += 1
time.sleep(1)
Expected behaviour
While code is running, pressing Ctrl+C in the USB REPL works as expected:
0
1
2
Traceback (most recent call last):
File "<stdin>", line 6, in <module>
KeyboardInterrupt:
>>>
Observed behaviour
While code is running, pressing Ctrl+C in the UART REPL fails to send the KeyboardInterrupt and halt execution.
Below, I pressed Ctrl+C a few times in the UART REPL, then once in the USB REPL. It then output extra >>>'s for each time I hit Ctrl+C in the UART REPL, indicating the KeyboardInterrupt's were getting buffered or something?
0
1
2
3
Traceback (most recent call last):
File "<stdin>", line 6, in <module>
KeyboardInterrupt:
>>>
>>>
>>>
>>>
>>>
Additional Information
Although the provided replication code uses UART, this also happens with a Bluetooth REPL connection and is actually what we need to be fixed. This was just the simplest way to replicate.
Code of Conduct
Yes, I agree