drivers: serial: Fix race condition in nRF5 UART TX

Fix a somewhat rare race condition when the thread gets
preempted in the middle of sending a byte through UART.

If the other thread also sends another byte through UART
and "consumes" the EVENTS_TXDRDY value, the first thread
will get stuck in the while loop forever.

By moving the reset to the function start, we guarantee that
the baseline state of EVENTS_TXRDY is 1. Therefore, the first
thread will continue normally when it executes again.

Signed-off-by: Thiago Silveira <thiago@exati.com.br>
This commit is contained in:
Thiago Silveira 2018-05-09 10:41:42 -03:00 committed by Carles Cufí
commit 05c45e359a

View file

@ -283,9 +283,6 @@ static int uart_nrf5_poll_in(struct device *dev, unsigned char *c)
/**
* @brief Output a character in polled mode.
*
* Checks if the transmitter is empty. If empty, a character is written to
* the data register.
*
* @param dev UART device struct
* @param c Character to send
*
@ -296,15 +293,27 @@ static unsigned char uart_nrf5_poll_out(struct device *dev,
{
volatile struct _uart *uart = UART_STRUCT(dev);
/* The UART API dictates that poll_out should wait for the transmitter
* to be empty before sending a character. However, without locking,
* this introduces a rare yet possible race condition if the thread is
* preempted between sending the byte and checking for completion.
* Because of this race condition, the while loop has to be placed
* after the write to TXD, and we can't wait for an empty transmitter
* before writing. This is a trade-off between losing a byte once in a
* blue moon against hanging up the whole thread permanently
*/
/* reset transmitter ready state */
uart->EVENTS_TXDRDY = 0;
/* send a character */
uart->TXD = (u8_t)c;
/* Wait for transmitter to be ready */
/* wait for transmitter to be ready */
while (!uart->EVENTS_TXDRDY) {
}
uart->EVENTS_TXDRDY = 0;
return c;
}