mirror of
https://github.com/apache/nuttx.git
synced 2026-05-26 10:46:28 +08:00
stm32wl5: fix unbuffered mode and other possible bugs
This patch fixes unbuffered mode so it actually works. Also, patch contains fixes for possible bugs that could result in deadlock or system hang in certain situations. Signed-off-by: Michał Łyszczek <michal.lyszczek@bofc.pl>
This commit is contained in:
committed by
Xiang Xiao
parent
3e43128f07
commit
4e967c67b4
@@ -132,6 +132,8 @@ int ipcc_poll(FAR struct file *filep, FAR struct pollfd *fds,
|
||||
/* Should immediately notify on any of the requested events? */
|
||||
|
||||
eventset = 0;
|
||||
|
||||
#ifdef CONFIG_IPCC_BUFFERED
|
||||
if (circbuf_used(&priv->ipcc->rxbuf) > 0)
|
||||
{
|
||||
eventset |= (fds->events & POLLIN);
|
||||
@@ -141,6 +143,7 @@ int ipcc_poll(FAR struct file *filep, FAR struct pollfd *fds,
|
||||
{
|
||||
eventset |= (fds->events & POLLOUT);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (eventset)
|
||||
{
|
||||
|
||||
@@ -122,6 +122,7 @@ ssize_t ipcc_read(FAR struct file *filep, FAR char *buffer,
|
||||
FAR struct ipcc_driver_s *priv;
|
||||
ssize_t nread;
|
||||
int ret;
|
||||
int flags;
|
||||
|
||||
/* Get our private data structure */
|
||||
|
||||
@@ -141,11 +142,33 @@ ssize_t ipcc_read(FAR struct file *filep, FAR char *buffer,
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
/* Disable interrupts, or we might get in situation when we:
|
||||
* - read 0 bytes from circbuf
|
||||
* - interrupt comes in
|
||||
* - it copies data to buffer and notifies blocked readers
|
||||
* (in this case sem count is 0, so no sem_post() is called)
|
||||
* - interrupt ends
|
||||
* - since we are in blocking mode, and we read 0 from buffer
|
||||
* we call sem_wait() and we hang in there cause rx interrupt
|
||||
* will not be triggered again.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
#ifdef CONFIG_IPCC_BUFFERED
|
||||
/* Data is buffered in interrupt handler, so we simply
|
||||
* have to return buffers content to the user
|
||||
*/
|
||||
|
||||
if (circbuf_used(&priv->ipcc->rxbuf))
|
||||
{
|
||||
/* There is some data on buffer, we are sure we won't block
|
||||
* so immediately leave critical section to not block other
|
||||
* more important drivers
|
||||
*/
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
if ((nread = circbuf_read(&priv->ipcc->rxbuf, buffer, buflen)) > 0)
|
||||
{
|
||||
/* got some data */
|
||||
@@ -176,18 +199,18 @@ ssize_t ipcc_read(FAR struct file *filep, FAR char *buffer,
|
||||
nxsem_post(&priv->exclsem);
|
||||
return nread;
|
||||
}
|
||||
|
||||
#else /* CONFIG_IPCC_BUFFERED */
|
||||
|
||||
/* Unbuffered read, read data directly from lower driver */
|
||||
|
||||
if ((nread = priv->ipcc->ops.read(&priv->ipcc, buffer, buflen)) != 0)
|
||||
if ((nread = priv->ipcc->ops.read(priv->ipcc, buffer, buflen)) != 0)
|
||||
{
|
||||
/* Got some data, return number of bytes read to the caller
|
||||
* --or--
|
||||
* read() returned error in which case return errno value
|
||||
*/
|
||||
|
||||
leave_critical_section(flags);
|
||||
nxsem_post(&priv->exclsem);
|
||||
return nread;
|
||||
}
|
||||
@@ -201,11 +224,15 @@ ssize_t ipcc_read(FAR struct file *filep, FAR char *buffer,
|
||||
* no data could be read
|
||||
*/
|
||||
|
||||
leave_critical_section(flags);
|
||||
nxsem_post(&priv->exclsem);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* We are in blocking mode, so we have to wait for data to arrive */
|
||||
/* We are in blocking mode, so we have to wait for data to arrive.
|
||||
* nxsem_wait() will atomically leave critical section for us so
|
||||
* we don't have to do it.
|
||||
*/
|
||||
|
||||
nxsem_post(&priv->exclsem);
|
||||
if ((ret = nxsem_wait(&priv->rxsem)))
|
||||
|
||||
@@ -124,6 +124,7 @@ ssize_t ipcc_write(FAR struct file *filep, FAR const char *buffer,
|
||||
FAR struct ipcc_driver_s *priv;
|
||||
ssize_t nwritten;
|
||||
int ret;
|
||||
int flags;
|
||||
|
||||
/* Get our private data structure */
|
||||
|
||||
@@ -143,6 +144,7 @@ ssize_t ipcc_write(FAR struct file *filep, FAR const char *buffer,
|
||||
|
||||
for (nwritten = 0; ; )
|
||||
{
|
||||
flags = enter_critical_section();
|
||||
#ifdef CONFIG_IPCC_BUFFERED
|
||||
/* Buffered write, if buffer is empty try to write directly to
|
||||
* IPCC memory, else buffer data in circbuf - it will be written
|
||||
@@ -169,6 +171,7 @@ ssize_t ipcc_write(FAR struct file *filep, FAR const char *buffer,
|
||||
*/
|
||||
|
||||
nxsem_post(&priv->exclsem);
|
||||
leave_critical_section(flags);
|
||||
return nwritten;
|
||||
}
|
||||
}
|
||||
@@ -191,13 +194,15 @@ ssize_t ipcc_write(FAR struct file *filep, FAR const char *buffer,
|
||||
/* All outstanding data has been copied to txbuffer, we're done */
|
||||
|
||||
nxsem_post(&priv->exclsem);
|
||||
leave_critical_section(flags);
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
#else /* CONFIG_IPCC_BUFFERED */
|
||||
/* Unbuffered write, write data directly to lower driver */
|
||||
|
||||
nwritten += priv->ipcc->ops.write(&priv->ipcc, buffer, buflen);
|
||||
nwritten += priv->ipcc->ops.write(priv->ipcc, buffer + nwritten,
|
||||
buflen - nwritten);
|
||||
if (nwritten == (ssize_t)buflen)
|
||||
{
|
||||
/* We've managed to write whole buffer to IPCC memory,
|
||||
@@ -210,6 +215,7 @@ ssize_t ipcc_write(FAR struct file *filep, FAR const char *buffer,
|
||||
*/
|
||||
|
||||
nxsem_post(&priv->exclsem);
|
||||
leave_critical_section(flags);
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
@@ -224,6 +230,7 @@ ssize_t ipcc_write(FAR struct file *filep, FAR const char *buffer,
|
||||
*/
|
||||
|
||||
nxsem_post(&priv->exclsem);
|
||||
leave_critical_section(flags);
|
||||
return nwritten ? nwritten : -EAGAIN;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user