drivers/pipes: using rmutex to protect pipe and avoid deadlock
nxsem_wait nuttx/sched/semaphore/sem_wait.c:176 nxmutex_lock nuttx/libs/libc/misc/lib_mutex.c:204 (discriminator 2) pipecommon_write nuttx/drivers/pipes/pipe_common.c:538 (discriminator 2) file_write nuttx/fs/vfs/fs_write.c:91 write nuttx/include/unistd.h:523 (discriminator 2) nxsig_deliver nuttx/sched/signal/sig_deliver.c:170 (discriminator 4) arm_sigdeliver nuttx/arch/arm/src/armv7-a/arm_sigdeliver.c:107 irq_waitlock nuttx/sched/irq/irq_csection.c:204 nxsem_post nuttx/sched/semaphore/sem_post.c:86 (discriminator 2) nxmutex_unlock nuttx/libs/libc/misc/lib_mutex.c:339 (discriminator 2) pipecommon_poll nuttx/drivers/pipes/pipe_common.c:769 file_poll nuttx/fs/vfs/fs_poll.c:321 poll_fdsetup nuttx/fs/vfs/fs_poll.c:194 poll nuttx/include/sys/poll.h:164 uv_run apps/system/libuv/libuv/src/unix/core.c:449 adb_hal_run apps/system/adb/microADB/hal/hal_uv.c:76 adbd_main apps/system/adb/adb_main.c:157 nxtask_startup nuttx/libs/libc/sched/task_startup.c:70 (discriminator 2) nxtask_start nuttx/sched/task/task_start.c:134 Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
This commit is contained in:
parent
786dabfb13
commit
0fb1dc2b93
|
@ -100,7 +100,7 @@ FAR struct pipe_dev_s *pipecommon_allocdev(size_t bufsize)
|
|||
{
|
||||
/* Initialize the private structure */
|
||||
|
||||
nxmutex_init(&dev->d_bflock);
|
||||
nxrmutex_init(&dev->d_bflock);
|
||||
nxsem_init(&dev->d_rdsem, 0, 0);
|
||||
nxsem_init(&dev->d_wrsem, 0, 0);
|
||||
dev->d_bufsize = bufsize;
|
||||
|
@ -115,7 +115,7 @@ FAR struct pipe_dev_s *pipecommon_allocdev(size_t bufsize)
|
|||
|
||||
void pipecommon_freedev(FAR struct pipe_dev_s *dev)
|
||||
{
|
||||
nxmutex_destroy(&dev->d_bflock);
|
||||
nxrmutex_destroy(&dev->d_bflock);
|
||||
nxsem_destroy(&dev->d_rdsem);
|
||||
nxsem_destroy(&dev->d_wrsem);
|
||||
kmm_free(dev);
|
||||
|
@ -134,14 +134,14 @@ int pipecommon_open(FAR struct file *filep)
|
|||
DEBUGASSERT(dev != NULL);
|
||||
|
||||
/* Make sure that we have exclusive access to the device structure. The
|
||||
* nxmutex_lock() call should fail if we are awakened by a signal or if the
|
||||
* thread was canceled.
|
||||
* nxrmutex_lock() call should fail if we are awakened by a signal or if
|
||||
* the thread was canceled.
|
||||
*/
|
||||
|
||||
ret = nxmutex_lock(&dev->d_bflock);
|
||||
ret = nxrmutex_lock(&dev->d_bflock);
|
||||
if (ret < 0)
|
||||
{
|
||||
ferr("ERROR: nxmutex_lock failed: %d\n", ret);
|
||||
ferr("ERROR: nxrmutex_lock failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ int pipecommon_open(FAR struct file *filep)
|
|||
ret = circbuf_init(&dev->d_buffer, NULL, dev->d_bufsize);
|
||||
if (ret < 0)
|
||||
{
|
||||
nxmutex_unlock(&dev->d_bflock);
|
||||
nxrmutex_unlock(&dev->d_bflock);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ int pipecommon_open(FAR struct file *filep)
|
|||
* on the pipe.
|
||||
*/
|
||||
|
||||
nxmutex_unlock(&dev->d_bflock);
|
||||
nxrmutex_unlock(&dev->d_bflock);
|
||||
|
||||
/* NOTE: d_wrsem is normally used to check if the write buffer is full
|
||||
* and wait for it being read and being able to receive more data. But,
|
||||
|
@ -207,14 +207,14 @@ int pipecommon_open(FAR struct file *filep)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* The nxmutex_lock() call should fail if we are awakened by a
|
||||
/* The nxrmutex_lock() call should fail if we are awakened by a
|
||||
* signal or if the task is canceled.
|
||||
*/
|
||||
|
||||
ret = nxmutex_lock(&dev->d_bflock);
|
||||
ret = nxrmutex_lock(&dev->d_bflock);
|
||||
if (ret < 0)
|
||||
{
|
||||
ferr("ERROR: nxmutex_lock failed: %d\n", ret);
|
||||
ferr("ERROR: nxrmutex_lock failed: %d\n", ret);
|
||||
|
||||
/* Immediately close the pipe that we just opened */
|
||||
|
||||
|
@ -251,7 +251,7 @@ int pipecommon_open(FAR struct file *filep)
|
|||
* on the pipe.
|
||||
*/
|
||||
|
||||
nxmutex_unlock(&dev->d_bflock);
|
||||
nxrmutex_unlock(&dev->d_bflock);
|
||||
|
||||
/* NOTE: d_rdsem is normally used when the read logic waits for more
|
||||
* data to be written. But until the first writer has opened the
|
||||
|
@ -273,14 +273,14 @@ int pipecommon_open(FAR struct file *filep)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* The nxmutex_lock() call should fail if we are awakened by a
|
||||
/* The nxrmutex_lock() call should fail if we are awakened by a
|
||||
* signal or if the task is canceled.
|
||||
*/
|
||||
|
||||
ret = nxmutex_lock(&dev->d_bflock);
|
||||
ret = nxrmutex_lock(&dev->d_bflock);
|
||||
if (ret < 0)
|
||||
{
|
||||
ferr("ERROR: nxmutex_lock failed: %d\n", ret);
|
||||
ferr("ERROR: nxrmutex_lock failed: %d\n", ret);
|
||||
|
||||
/* Immediately close the pipe that we just opened */
|
||||
|
||||
|
@ -289,7 +289,7 @@ int pipecommon_open(FAR struct file *filep)
|
|||
}
|
||||
}
|
||||
|
||||
nxmutex_unlock(&dev->d_bflock);
|
||||
nxrmutex_unlock(&dev->d_bflock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -310,7 +310,7 @@ int pipecommon_close(FAR struct file *filep)
|
|||
* I've never seen anyone check that.
|
||||
*/
|
||||
|
||||
ret = nxmutex_lock(&dev->d_bflock);
|
||||
ret = nxrmutex_lock(&dev->d_bflock);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* The close will not be performed if the task was canceled */
|
||||
|
@ -398,7 +398,7 @@ int pipecommon_close(FAR struct file *filep)
|
|||
#endif
|
||||
}
|
||||
|
||||
nxmutex_unlock(&dev->d_bflock);
|
||||
nxrmutex_unlock(&dev->d_bflock);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -422,7 +422,7 @@ ssize_t pipecommon_read(FAR struct file *filep, FAR char *buffer, size_t len)
|
|||
|
||||
/* Make sure that we have exclusive access to the device structure */
|
||||
|
||||
ret = nxmutex_lock(&dev->d_bflock);
|
||||
ret = nxrmutex_lock(&dev->d_bflock);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* May fail because a signal was received or if the task was
|
||||
|
@ -440,7 +440,7 @@ ssize_t pipecommon_read(FAR struct file *filep, FAR char *buffer, size_t len)
|
|||
|
||||
if (dev->d_nwriters <= 0 && PIPE_IS_POLICY_0(dev->d_flags))
|
||||
{
|
||||
nxmutex_unlock(&dev->d_bflock);
|
||||
nxrmutex_unlock(&dev->d_bflock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -448,16 +448,16 @@ ssize_t pipecommon_read(FAR struct file *filep, FAR char *buffer, size_t len)
|
|||
|
||||
if (filep->f_oflags & O_NONBLOCK)
|
||||
{
|
||||
nxmutex_unlock(&dev->d_bflock);
|
||||
nxrmutex_unlock(&dev->d_bflock);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* Otherwise, wait for something to be written to the pipe */
|
||||
|
||||
nxmutex_unlock(&dev->d_bflock);
|
||||
nxrmutex_unlock(&dev->d_bflock);
|
||||
ret = nxsem_wait(&dev->d_rdsem);
|
||||
|
||||
if (ret < 0 || (ret = nxmutex_lock(&dev->d_bflock)) < 0)
|
||||
if (ret < 0 || (ret = nxrmutex_lock(&dev->d_bflock)) < 0)
|
||||
{
|
||||
/* May fail because a signal was received or if the task was
|
||||
* canceled.
|
||||
|
@ -488,7 +488,7 @@ ssize_t pipecommon_read(FAR struct file *filep, FAR char *buffer, size_t len)
|
|||
|
||||
pipecommon_wakeup(&dev->d_wrsem);
|
||||
|
||||
nxmutex_unlock(&dev->d_bflock);
|
||||
nxrmutex_unlock(&dev->d_bflock);
|
||||
pipe_dumpbuffer("From PIPE:", buffer, nread);
|
||||
return nread;
|
||||
}
|
||||
|
@ -517,7 +517,7 @@ ssize_t pipecommon_write(FAR struct file *filep, FAR const char *buffer,
|
|||
}
|
||||
|
||||
/* At present, this method cannot be called from interrupt handlers. That
|
||||
* is because it calls nxmutex_lock() and nxmutex_lock() cannot be called
|
||||
* is because it calls nxrmutex_lock() and nxrmutex_lock() cannot be called
|
||||
* form interrupt level. This actually happens fairly commonly
|
||||
* IF [a-z]err() is called from interrupt handlers and stdout is being
|
||||
* redirected via a pipe. In that case, the debug output will try to go
|
||||
|
@ -533,7 +533,7 @@ ssize_t pipecommon_write(FAR struct file *filep, FAR const char *buffer,
|
|||
|
||||
/* Make sure that we have exclusive access to the device structure */
|
||||
|
||||
ret = nxmutex_lock(&dev->d_bflock);
|
||||
ret = nxrmutex_lock(&dev->d_bflock);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* May fail because a signal was received or if the task was
|
||||
|
@ -556,7 +556,7 @@ ssize_t pipecommon_write(FAR struct file *filep, FAR const char *buffer,
|
|||
|
||||
if (dev->d_nreaders <= 0 && PIPE_IS_POLICY_0(dev->d_flags))
|
||||
{
|
||||
nxmutex_unlock(&dev->d_bflock);
|
||||
nxrmutex_unlock(&dev->d_bflock);
|
||||
return nwritten == 0 ? -EPIPE : nwritten;
|
||||
}
|
||||
|
||||
|
@ -589,7 +589,7 @@ ssize_t pipecommon_write(FAR struct file *filep, FAR const char *buffer,
|
|||
|
||||
/* Return the number of bytes written */
|
||||
|
||||
nxmutex_unlock(&dev->d_bflock);
|
||||
nxrmutex_unlock(&dev->d_bflock);
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
@ -627,7 +627,7 @@ ssize_t pipecommon_write(FAR struct file *filep, FAR const char *buffer,
|
|||
nwritten = -EAGAIN;
|
||||
}
|
||||
|
||||
nxmutex_unlock(&dev->d_bflock);
|
||||
nxrmutex_unlock(&dev->d_bflock);
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
|
@ -635,9 +635,9 @@ ssize_t pipecommon_write(FAR struct file *filep, FAR const char *buffer,
|
|||
* the pipe
|
||||
*/
|
||||
|
||||
nxmutex_unlock(&dev->d_bflock);
|
||||
nxrmutex_unlock(&dev->d_bflock);
|
||||
ret = nxsem_wait(&dev->d_wrsem);
|
||||
if (ret < 0 || (ret = nxmutex_lock(&dev->d_bflock)) < 0)
|
||||
if (ret < 0 || (ret = nxrmutex_lock(&dev->d_bflock)) < 0)
|
||||
{
|
||||
/* Either call nxsem_wait may fail because a signal was
|
||||
* received or if the task was canceled.
|
||||
|
@ -667,7 +667,7 @@ int pipecommon_poll(FAR struct file *filep, FAR struct pollfd *fds,
|
|||
|
||||
/* Are we setting up the poll? Or tearing it down? */
|
||||
|
||||
ret = nxmutex_lock(&dev->d_bflock);
|
||||
ret = nxrmutex_lock(&dev->d_bflock);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
|
@ -764,7 +764,7 @@ int pipecommon_poll(FAR struct file *filep, FAR struct pollfd *fds,
|
|||
}
|
||||
|
||||
errout:
|
||||
nxmutex_unlock(&dev->d_bflock);
|
||||
nxrmutex_unlock(&dev->d_bflock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -787,7 +787,7 @@ int pipecommon_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
}
|
||||
#endif
|
||||
|
||||
ret = nxmutex_lock(&dev->d_bflock);
|
||||
ret = nxrmutex_lock(&dev->d_bflock);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
|
@ -902,7 +902,7 @@ int pipecommon_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
break;
|
||||
}
|
||||
|
||||
nxmutex_unlock(&dev->d_bflock);
|
||||
nxrmutex_unlock(&dev->d_bflock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -919,7 +919,7 @@ int pipecommon_unlink(FAR struct inode *inode)
|
|||
DEBUGASSERT(inode->i_private);
|
||||
dev = inode->i_private;
|
||||
|
||||
ret = nxmutex_lock(&dev->d_bflock);
|
||||
ret = nxrmutex_lock(&dev->d_bflock);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
|
@ -935,7 +935,7 @@ int pipecommon_unlink(FAR struct inode *inode)
|
|||
/* Mark the pipe unlinked */
|
||||
|
||||
PIPE_UNLINK(dev->d_flags);
|
||||
nxmutex_unlock(&dev->d_bflock);
|
||||
nxrmutex_unlock(&dev->d_bflock);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ typedef uint8_t pipe_ndx_t; /* 8-bit index */
|
|||
|
||||
struct pipe_dev_s
|
||||
{
|
||||
mutex_t d_bflock; /* Used to serialize access to d_buffer and indices */
|
||||
rmutex_t d_bflock; /* Used to serialize access to d_buffer and indices */
|
||||
sem_t d_rdsem; /* Empty buffer - Reader waits for data write AND
|
||||
* block O_RDONLY open until there is at least one writer */
|
||||
sem_t d_wrsem; /* Full buffer - Writer waits for data read AND
|
||||
|
|
Loading…
Reference in New Issue