drivers/serial: fix race condition in multi-thread write

if multiple threads are doing serial read/write at the same time,
the driver will only wake up one of the thread, which will cause
other threads fail to be woken up in time and cause blocking

Signed-off-by: chao an <anchao@xiaomi.com>
This commit is contained in:
chao an 2023-05-16 14:37:41 +08:00 committed by Alin Jerpelea
parent 23ad4700a9
commit 6be363ff35
6 changed files with 21 additions and 55 deletions

View File

@ -128,8 +128,6 @@ static struct ez80_dev_s g_uart0priv =
static uart_dev_t g_uart0port =
{
0, /* open_count */
false, /* xmitwaiting */
false, /* recvwaiting */
#ifdef CONFIG_UART0_SERIAL_CONSOLE
true, /* isconsole */
#else

View File

@ -136,8 +136,6 @@ static const struct z180_dev_s g_scc_priv =
static uart_dev_t g_scc_port =
{
0, /* open_count */
false, /* xmitwaiting */
false, /* recvwaiting */
#ifdef CONFIG_Z180_SCC_SERIAL_CONSOLE
true, /* isconsole */
#else
@ -182,8 +180,6 @@ static const struct z180_dev_s g_escca_priv =
static uart_dev_t g_escca_port =
{
0, /* open_count */
false, /* xmitwaiting */
false, /* recvwaiting */
#ifdef CONFIG_Z180_ESCCA_SERIAL_CONSOLE
true, /* isconsole */
#else
@ -228,8 +224,6 @@ static const struct z180_dev_s g_esccb_priv =
static uart_dev_t g_escca_port =
{
0, /* open_count */
false, /* xmitwaiting */
false, /* recvwaiting */
#ifdef CONFIG_Z180_ESCCA_SERIAL_CONSOLE
true, /* isconsole */
#else

View File

@ -138,8 +138,6 @@ static struct z8_uart_s g_uart0priv =
static uart_dev_t g_uart0port =
{
0, /* open_count */
false, /* xmitwaiting */
false, /* recvwaiting */
#ifdef CONFIG_UART0_SERIAL_CONSOLE
true, /* isconsole */
#else
@ -185,8 +183,6 @@ static struct z8_uart_s g_uart1priv =
static uart_dev_t g_uart1port =
{
0, /* open_count */
false, /* xmitwaiting */
false, /* recvwaiting */
#ifdef CONFIG_UART1_SERIAL_CONSOLE
true, /* isconsole */
#else

View File

@ -90,8 +90,6 @@ static char g_uarttxbuffer[CONFIG_UART_TXBUFSIZE];
static uart_dev_t g_uartport =
{
0, /* open_count */
false, /* xmitwaiting */
false, /* recvwaiting */
true, /* isconsole */
{ 1 }, /* closesem */
{ 0 }, /* xmitsem */

View File

@ -225,10 +225,6 @@ static int uart_putxmitchar(FAR uart_dev_t *dev, int ch, bool oktoblock)
#endif
else
{
/* Inform the interrupt level logic that we are waiting. */
dev->xmitwaiting = true;
/* Wait for some characters to be sent from the buffer with
* the TX interrupt enabled. When the TX interrupt is enabled,
* uart_xmitchars() should execute and remove some of the data
@ -415,10 +411,6 @@ static int uart_tcdrain(FAR uart_dev_t *dev,
ret = OK;
while (ret >= 0 && dev->xmit.head != dev->xmit.tail)
{
/* Inform the interrupt level logic that we are waiting. */
dev->xmitwaiting = true;
/* Wait for some characters to be sent from the buffer with
* the TX interrupt enabled. When the TX interrupt is
* enabled, uart_xmitchars() should execute and remove some
@ -1048,8 +1040,6 @@ static ssize_t uart_read(FAR struct file *filep,
* thread goes to sleep.
*/
dev->recvwaiting = true;
#ifdef CONFIG_SERIAL_TERMIOS
dev->minrecv = MIN(buflen - recvd, dev->minread - recvd);
if (dev->timeout)
@ -1064,7 +1054,6 @@ static ssize_t uart_read(FAR struct file *filep,
}
}
dev->recvwaiting = false;
leave_critical_section(flags);
/* Was a signal received while waiting for data to be
@ -1786,6 +1775,23 @@ static void uart_launch(void)
}
#endif
static void uart_wakeup(FAR sem_t *sem)
{
int sval;
if (nxsem_get_value(sem, &sval) != OK)
{
return;
}
/* Yes... wake up all waiting threads */
while (sval++ < 1)
{
nxsem_post(sem);
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -1865,13 +1871,7 @@ void uart_datareceived(FAR uart_dev_t *dev)
/* Is there a thread waiting for read data? */
if (dev->recvwaiting)
{
/* Yes... wake it up */
dev->recvwaiting = false;
nxsem_post(&dev->recvsem);
}
uart_wakeup(&dev->recvsem);
#if defined(CONFIG_PM) && defined(CONFIG_SERIAL_CONSOLE)
/* Call pm_activity when characters are received on the console device */
@ -1903,13 +1903,7 @@ void uart_datasent(FAR uart_dev_t *dev)
/* Is there a thread waiting for space in xmit.buffer? */
if (dev->xmitwaiting)
{
/* Yes... wake it up */
dev->xmitwaiting = false;
nxsem_post(&dev->xmitsem);
}
uart_wakeup(&dev->xmitsem);
}
/****************************************************************************
@ -1957,23 +1951,11 @@ void uart_connected(FAR uart_dev_t *dev, bool connected)
/* Is there a thread waiting for space in xmit.buffer? */
if (dev->xmitwaiting)
{
/* Yes... wake it up */
dev->xmitwaiting = false;
nxsem_post(&dev->xmitsem);
}
uart_wakeup(&dev->xmitsem);
/* Is there a thread waiting for read data? */
if (dev->recvwaiting)
{
/* Yes... wake it up */
dev->recvwaiting = false;
nxsem_post(&dev->recvsem);
}
uart_wakeup(&dev->recvsem);
}
leave_critical_section(flags);

View File

@ -272,8 +272,6 @@ struct uart_dev_s
uint8_t open_count; /* Number of times the device has been opened */
uint8_t escape; /* Number of the character to be escaped */
volatile bool xmitwaiting; /* true: User waiting for space in xmit.buffer */
volatile bool recvwaiting; /* true: User waiting for data in recv.buffer */
#ifdef CONFIG_SERIAL_REMOVABLE
volatile bool disconnected; /* true: Removable device is not connected */
#endif