-
Notifications
You must be signed in to change notification settings - Fork 8k
Description
Environment
- Module or chip used: [ESP32-WROOM-32]
- IDF version: found in
v4.0.1, also present in current "master" (v4.3-dev-2399-gf3adbbb8eas of 2021-01-13)
Problem Description
I am developing a project using the ESP32 port of MicroPython; the main task has to process chars from the serial port when they are available. MicroPython does not have non-blocking file I/O, but offers a select() operation that can be used to query if a stream is ready for reading; the assumption being that when so, at least a single byte can be read without blocking.
Very rarely, though, this select() was returning the UART stream as ready, even though a subsequent read operation had 0 bytes available. This caused the Python application to hang until data was actually sent to the serial port.
Tracing the issue in the Micropython and then ESP-IDF sources led to identification of an issue in the current implementation of the uart_get_buffered_data_len() API function.
Expected Behavior
uart_get_buffered_data_len()should always fill itssizeparameter either with 0 or with the number of bytes available in the requested UART.
Actual Behavior
uart_get_buffered_data_len()may return a garbage value insizeif a different execution thread updates the internal state of the UART while this function is being run.
Steps / code to reproduce
I assume the following snippet for a given uart_num would eventually show the issue if left running long enough (no input is required):
while (1) {
size_t data_len;
if (uart_get_buffered_data_len(uart_num, &data_len) == ESP_OK) {
uint8_t buf;
int ret = uart_read_bytes(uart_num, &buf, 1, 0);
if (ret != 1) ESP32_LOGW("data_len %u but read_bytes %i?", data_len, ret);
}
}Proposed fix
I will shortly provide a pull request adding the missing critical section barriers; these are already present in all other functions accessing the UART state in uart.c.