forked from nuttx/nuttx-update
Pipes/FIFOs: Implement the unlink method. If the pipe/FIFO is unlinked, it will marked the pipe/FIFO as unliked. If/when all open references to the driver are closed, all of the driver resources will be freed.
This commit is contained in:
parent
05e82a88a7
commit
39a5238c43
4 changed files with 116 additions and 43 deletions
|
@ -1,7 +1,7 @@
|
|||
/****************************************************************************
|
||||
* drivers/pipes/fifo.c
|
||||
*
|
||||
* Copyright (C) 2008-2009, 2014 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2008-2009, 2014-2015 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -73,10 +73,11 @@ static const struct file_operations fifo_fops =
|
|||
pipecommon_read, /* read */
|
||||
pipecommon_write, /* write */
|
||||
0, /* seek */
|
||||
pipecommon_ioctl /* ioctl */
|
||||
pipecommon_ioctl, /* ioctl */
|
||||
#ifndef CONFIG_DISABLE_POLL
|
||||
, pipecommon_poll /* poll */
|
||||
pipecommon_poll, /* poll */
|
||||
#endif
|
||||
pipecommon_unlink /* unlink */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -92,15 +93,15 @@ static const struct file_operations fifo_fops =
|
|||
*
|
||||
* Description:
|
||||
* mkfifo() makes a FIFO device driver file with name 'pathname.' Unlike
|
||||
* Linux, a NuttX FIFO is not a special file type but simply a device driver
|
||||
* instance. 'mode' specifies the FIFO's permissions.
|
||||
* Linux, a NuttX FIFO is not a special file type but simply a device
|
||||
* driver instance. 'mode' specifies the FIFO's permissions.
|
||||
*
|
||||
* Once the FIFO has been created by mkfifo(), any thread can open it for
|
||||
* reading or writing, in the same way as an ordinary file. However, it must
|
||||
* have been opened from both reading and writing before input or output
|
||||
* can be performed. This FIFO implementation will block all attempts to
|
||||
* open a FIFO read-only until at least one thread has opened the FIFO for
|
||||
* writing.
|
||||
* reading or writing, in the same way as an ordinary file. However, it
|
||||
* must have been opened from both reading and writing before input or
|
||||
* output can be performed. This FIFO implementation will block all
|
||||
* attempts to open a FIFO read-only until at least one thread has opened
|
||||
* the FIFO for writing.
|
||||
*
|
||||
* If all threads that write to the FIFO have closed, subsequent calls to
|
||||
* read() on the FIFO will return 0 (end-of-file).
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/****************************************************************************
|
||||
* drivers/pipes/pipe.c
|
||||
*
|
||||
* Copyright (C) 2008-2009 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2008-2009, 2015 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -82,10 +82,11 @@ static const struct file_operations pipe_fops =
|
|||
pipecommon_read, /* read */
|
||||
pipecommon_write, /* write */
|
||||
0, /* seek */
|
||||
pipecommon_ioctl /* ioctl */
|
||||
pipecommon_ioctl, /* ioctl */
|
||||
#ifndef CONFIG_DISABLE_POLL
|
||||
, pipecommon_poll /* poll */
|
||||
pipecommon_poll, /* poll */
|
||||
#endif
|
||||
pipecommon_unlink /* unlink */
|
||||
};
|
||||
|
||||
static sem_t g_pipesem = SEM_INITIALIZER(1);
|
||||
|
@ -124,7 +125,9 @@ static inline int pipe_allocate(void)
|
|||
|
||||
static inline void pipe_free(int pipeno)
|
||||
{
|
||||
int ret = sem_wait(&g_pipesem);
|
||||
int ret;
|
||||
|
||||
ret = sem_wait(&g_pipesem);
|
||||
if (ret == 0)
|
||||
{
|
||||
g_pipeset &= ~(1 << pipeno);
|
||||
|
@ -138,17 +141,11 @@ static inline void pipe_free(int pipeno)
|
|||
|
||||
static int pipe_close(FAR struct file *filep)
|
||||
{
|
||||
struct inode *inode = filep->f_inode;
|
||||
struct pipe_dev_s *dev = inode->i_private;
|
||||
int ret;
|
||||
FAR struct inode *inode = filep->f_inode;
|
||||
FAR struct pipe_dev_s *dev = inode->i_private;
|
||||
int ret;
|
||||
|
||||
/* Some sanity checking */
|
||||
#if CONFIG_DEBUG
|
||||
if (!dev)
|
||||
{
|
||||
return -EBADF;
|
||||
}
|
||||
#endif
|
||||
DEBUGASSERT(dev);
|
||||
|
||||
/* Perform common close operations */
|
||||
|
||||
|
@ -171,8 +168,8 @@ static int pipe_close(FAR struct file *filep)
|
|||
* Name: pipe
|
||||
*
|
||||
* Description:
|
||||
* pipe() creates a pair of file descriptors, pointing to a pipe inode, and
|
||||
* places them in the array pointed to by 'fd'. fd[0] is for reading,
|
||||
* pipe() creates a pair of file descriptors, pointing to a pipe inode,
|
||||
* and places them in the array pointed to by 'fd'. fd[0] is for reading,
|
||||
* fd[1] is for writing.
|
||||
*
|
||||
* Inputs:
|
||||
|
@ -187,7 +184,7 @@ static int pipe_close(FAR struct file *filep)
|
|||
|
||||
int pipe(int fd[2])
|
||||
{
|
||||
struct pipe_dev_s *dev = NULL;
|
||||
FAR struct pipe_dev_s *dev = NULL;
|
||||
char devname[16];
|
||||
int pipeno;
|
||||
int err;
|
||||
|
@ -272,15 +269,19 @@ int pipe(int fd[2])
|
|||
|
||||
errout_with_wrfd:
|
||||
close(fd[1]);
|
||||
|
||||
errout_with_driver:
|
||||
unregister_driver(devname);
|
||||
|
||||
errout_with_dev:
|
||||
if (dev)
|
||||
{
|
||||
pipecommon_freedev(dev);
|
||||
}
|
||||
|
||||
errout_with_pipe:
|
||||
pipe_free(pipeno);
|
||||
|
||||
errout:
|
||||
set_errno(err);
|
||||
return ERROR;
|
||||
|
|
|
@ -172,10 +172,10 @@ FAR struct pipe_dev_s *pipecommon_allocdev(void)
|
|||
|
||||
void pipecommon_freedev(FAR struct pipe_dev_s *dev)
|
||||
{
|
||||
sem_destroy(&dev->d_bfsem);
|
||||
sem_destroy(&dev->d_rdsem);
|
||||
sem_destroy(&dev->d_wrsem);
|
||||
kmm_free(dev);
|
||||
sem_destroy(&dev->d_bfsem);
|
||||
sem_destroy(&dev->d_rdsem);
|
||||
sem_destroy(&dev->d_wrsem);
|
||||
kmm_free(dev);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -203,9 +203,9 @@ int pipecommon_open(FAR struct file *filep)
|
|||
return -get_errno();
|
||||
}
|
||||
|
||||
/* If this the first reference on the device, then allocate the buffer. In the
|
||||
* case of d_policy == 1, the buffer already be present when the pipe is
|
||||
* first opened.
|
||||
/* If this the first reference on the device, then allocate the buffer.
|
||||
* In the case of policy 1, the buffer already be present when the pipe
|
||||
* is first opened.
|
||||
*/
|
||||
|
||||
if (dev->d_refs == 0 && dev->d_buffer == NULL)
|
||||
|
@ -303,7 +303,7 @@ int pipecommon_close(FAR struct file *filep)
|
|||
pipecommon_semtake(&dev->d_bfsem);
|
||||
|
||||
/* Decrement the number of references on the pipe. Check if there are
|
||||
* still oustanding references to the pipe.
|
||||
* still outstanding references to the pipe.
|
||||
*/
|
||||
|
||||
/* Check if the decremented reference count would go to zero */
|
||||
|
@ -331,12 +331,12 @@ int pipecommon_close(FAR struct file *filep)
|
|||
}
|
||||
|
||||
/* What is the buffer management policy? Do we free the buffe when the
|
||||
* last client closes the pipe (d_policy == 0), or when the buffer becomes
|
||||
* empty (d_policy). In the latter case, the buffer data will remain
|
||||
* valid and can be obtained when the pipe is re-opened.
|
||||
* last client closes the pipe policy 0, or when the buffer becomes empty.
|
||||
* In the latter case, the buffer data will remain valid and can be
|
||||
* obtained when the pipe is re-opened.
|
||||
*/
|
||||
|
||||
else if (dev->d_policy == 0 || dev->d_wrndx == dev->d_rdndx)
|
||||
else if (PIPE_IS_POLICY_0(dev->d_flags) || dev->d_wrndx == dev->d_rdndx)
|
||||
{
|
||||
/* Policy 0 or the buffer is empty ... deallocate the buffer now. */
|
||||
|
||||
|
@ -349,6 +349,16 @@ int pipecommon_close(FAR struct file *filep)
|
|||
dev->d_rdndx = 0;
|
||||
dev->d_refs = 0;
|
||||
dev->d_nwriters = 0;
|
||||
|
||||
/* If, in addition, we have been unlinked, then also need to free the
|
||||
* device structure as well to prevent a memory leak.
|
||||
*/
|
||||
|
||||
if (PIPE_IS_UNLINKED(dev->d_flags))
|
||||
{
|
||||
pipecommon_freedev(dev);
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
sem_post(&dev->d_bfsem);
|
||||
|
@ -678,10 +688,57 @@ int pipecommon_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
|
||||
if (cmd == PIPEIOC_POLICY)
|
||||
{
|
||||
dev->d_policy = (arg != 0);
|
||||
if (arg != 0)
|
||||
{
|
||||
PIPE_POLICY_1(dev->d_flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
PIPE_POLICY_0(dev->d_flags);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pipecommon_unlink
|
||||
****************************************************************************/
|
||||
|
||||
int pipecommon_unlink(FAR void *priv)
|
||||
{
|
||||
/* The value passed to pipcommon_unlink is the private data pointer from
|
||||
* the inode that is being unlinked. If there are no open references to
|
||||
* the driver, then we must free up all resources used by the driver now.
|
||||
*/
|
||||
|
||||
FAR struct pipe_dev_s *dev = (FAR struct pipe_dev_s *)priv;
|
||||
|
||||
DEBUGASSERT(dev);
|
||||
|
||||
/* Mark the pipe unlinked */
|
||||
|
||||
PIPE_UNLINK(dev->d_flags);
|
||||
|
||||
/* Are the any open references to the driver? */
|
||||
|
||||
if (dev->d_refs == 0)
|
||||
{
|
||||
/* No.. free the buffer (if there is one) */
|
||||
|
||||
if (dev->d_buffer)
|
||||
{
|
||||
kmm_free(dev->d_buffer);
|
||||
}
|
||||
|
||||
/* And free the device structure. */
|
||||
|
||||
pipecommon_freedev(dev);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DEV_PIPE_SIZE > 0 */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/****************************************************************************
|
||||
* drivers/pipe/pipe_common.h
|
||||
*
|
||||
* Copyright (C) 2008-2009 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2008-2009, 2015 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -67,6 +67,20 @@
|
|||
|
||||
#define CONFIG_DEV_PIPE_MAXUSER 255
|
||||
|
||||
/* d_flags values */
|
||||
|
||||
#define PIPE_FLAG_POLICY (1 << 0) /* Bit 0: Policy=Free buffer when empty */
|
||||
#define PIPE_FLAG_UNLINKED (1 << 1) /* Bit 1: The driver has been unlinked */
|
||||
|
||||
#define PIPE_POLICY_0(f) do { (f) &= ~PIPE_FLAG_POLICY; } while (0)
|
||||
#define PIPE_POLICY_1(f) do { (f) |= PIPE_FLAG_POLICY; } while (0)
|
||||
#define PIPE_IS_POLICY_0(f) (((f) & PIPE_FLAG_POLICY) == 0)
|
||||
#define PIPE_IS_POLICY_1(f) (((f) & PIPE_FLAG_POLICY) != 0)
|
||||
|
||||
#define PIPE_UNLINK(f) do { (f) |= PIPE_FLAG_UNLINKED; } while (0)
|
||||
#define PIPE_IS_UNLINKED(f) (((f) & PIPE_FLAG_UNLINKED) != 0)
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
@ -96,7 +110,7 @@ struct pipe_dev_s
|
|||
uint8_t d_refs; /* References counts on pipe (limited to 255) */
|
||||
uint8_t d_nwriters; /* Number of reference counts for write access */
|
||||
uint8_t d_pipeno; /* Pipe minor number */
|
||||
bool d_policy; /* Buffer policy: 0=free on close; 1=free on empty */
|
||||
uint8_t d_flags; /* See PIPE_FLAG_* definitions */
|
||||
uint8_t *d_buffer; /* Buffer allocated when device opened */
|
||||
|
||||
/* The following is a list if poll structures of threads waiting for
|
||||
|
@ -127,11 +141,11 @@ int pipecommon_close(FAR struct file *filep);
|
|||
ssize_t pipecommon_read(FAR struct file *, FAR char *, size_t);
|
||||
ssize_t pipecommon_write(FAR struct file *, FAR const char *, size_t);
|
||||
int pipecommon_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
|
||||
|
||||
#ifndef CONFIG_DISABLE_POLL
|
||||
int pipecommon_poll(FAR struct file *filep, FAR struct pollfd *fds,
|
||||
bool setup);
|
||||
#endif
|
||||
int pipecommon_unlink(FAR void *priv);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
|
|
Loading…
Reference in a new issue