Skip to content

uart: uart_get_buffered_data_len() very rarely fails (IDFGH-4580) #6397

@pillo79

Description

@pillo79

Environment

  • Module or chip used: [ESP32-WROOM-32]
  • IDF version: found in v4.0.1, also present in current "master" (v4.3-dev-2399-gf3adbbb8e as 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 its size parameter 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 in size if 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions