Support stdio drivers with blocking character input #1020
Labels
No labels
bazel
bluetooth
board settings
boot_stage2
bug
build
c++
can't reproduce
clang
clib-interface
cmsis
code cleanliness
code size
compiler version issues
cyw43_driver
debug
discussion
documentation
duplicate
dynamic_clock
elf2uf2
enhancement
errata
filesystem
flash layout
floating point
FreeRTOS
hardware_adc
hardware_claim
hardware_clocks
hardware_dma
hardware_exception
hardware_flash
hardware_gpio
hardware_i2c
hardware_irq
hardware_pio
hardware_pwm
hardware_rcp
hardware_rtc
hardware_spi
hardware_sync
hardware_uart
hardware_vreg
hardware_watchdog
hardware_xosc
help wanted
host
IAR
installation
invalid
linker scripts
lto
lwip
mbedtls
missing API
needs reporter detail
networking
newlib
newlib-multicore
non-c
non-cmake
non-gcc
openocd
orphan PR
OS integration
pico_async_context
pico_base
pico_binary_info
pico_flash
picolibc
pico_lwip
pico_malloc
pico_multicore
pico_printf
pico_runtime
pico_stdio
pico_stdio_usb
pico_sync
pico_time
pico_util
pioasm
port
question
review
review2
rtos interop
runtime init
static library
svd
test
tinyusb
vscode
wifi integration
wontfix
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
gh-raspberrypi/pico-sdk#1020
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The signature of stdio_driver_t::in_chars is:
I would like to add another entry point to stdio_driver_t:
The reason is, the former makes it awkward to implement a blocking stdio driver for an RTOS. Here is what I would like to write for qOS:
Without the added
untilparameter, the options are to haveqos_await_irq()not block, in which case stdio input busy waits or to haveqos_await_irq()timeout after an arbitrary amount of time, such as one second, which reduces the precision of the timeout passed togetchar_timeout_us().I have an alternative suggestion, which I think is more satisfying. Instead of adding in_chars_timeout_us, add this new entry point:
The contract is, it must return if/when a character is readable, it should return after timeout and it may return spuriously. An RTOS might implement it like this:
A busy waiting driver might implement it like this:
And this is the default implementation if the entry point is null. I've moved the busy_wait_us call out of stdio_get_until() into await_char_readable() because it is unnecessary and undesirable to busy wait if there's an RTOS.
This also solves the problem of what to do if there are >1 drivers; call await_char_readable() only if there is one driver and fall back on busy waiting if there are >1. I would rather do something better for the >1 case though.
An idea for making the >1 driver case better... If there is only one driver and it implements await_char_readable() then do things same as above. If there are >1 drivers or if the only driver does not implement await_char_readable(), then have stdio_get_until() call a macro pico_yield() in place of busy_wait_us(1). Something like:
By default, pico_yield() just calls busy_wait_us(1) as before:
But, similar to the lock_internal macros, an RTOS may define it to something appropriate to prevent lower priority tasks from starving:
pico_yield() could potentially find other uses in the SDK.
With these things done, if there is only one driver, an RTOS could wait for stdio input while in sleep mode. With >1 driver, it wouldn't be able to sleep while waiting for input but at least lower priority tasks wouldn't starve.
This is closely related to issue #547, which suggests this is also a problem for FreeRTOS.
Two desirable outcomes that I haven't considered so far are: 1) It would be good if vanilla SDK without an RTOS could sleep while waiting for stdio input. 2) It would be good if an RTOS didn't have to implement a whole new stdio driver to make blocking work.
A blocking stdio UART driver for the SDK might look like this:
This must not be a breaking change, so add a function to opt-in to blocking mode. Caller agrees that it ought not to install an exclusive UART IRQ handler on this core or any UART IRQ handler on the other core or mess with the UART IRQ NVIC registers.
An RTOS replaces these macros. All stdio drivers share the same the same event synchronization object to allow blocking even when there are several drivers.
FreeRTOS might do something similar with xEventGroupSetBits(), xEventGroupSetBitsFromISR() and xEventGroupWaitBits();
Then with changes along these lines working, hopefully:
Here's a prototype of above scheme that seems to kind of work:
github.com/alastairpatrick/pico-sdk@8a5e920ca9. I also made stdio_uart_out_chars() potentially blocking since RTOSes might want to run lower priority tasks while the UART TX FIFO empties.