2012-11-22 16:43:40 +08:00
|
|
|
/*
|
2021-03-08 18:19:04 +08:00
|
|
|
* Copyright (c) 2006-2021, RT-Thread Development Team
|
2012-11-22 16:43:40 +08:00
|
|
|
*
|
2018-10-14 19:37:18 +08:00
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
2012-11-22 16:43:40 +08:00
|
|
|
*
|
|
|
|
* Change Logs:
|
|
|
|
* Date Author Notes
|
|
|
|
* 2012-09-30 Bernard first version.
|
2017-11-08 09:38:18 +08:00
|
|
|
* 2017-11-08 JasonJiaJie fix memory leak issue when close a pipe.
|
2012-11-22 16:43:40 +08:00
|
|
|
*/
|
|
|
|
#include <rthw.h>
|
|
|
|
#include <rtdevice.h>
|
2017-12-31 23:51:57 +08:00
|
|
|
#include <stdint.h>
|
2021-06-12 18:11:51 +08:00
|
|
|
#include <sys/errno.h>
|
2017-10-17 22:27:06 +08:00
|
|
|
|
2021-11-24 22:14:46 +08:00
|
|
|
#ifdef RT_USING_POSIX_DEVIO
|
2017-10-15 22:56:46 +08:00
|
|
|
#include <dfs_file.h>
|
|
|
|
#include <dfs_posix.h>
|
2021-09-11 23:48:14 +08:00
|
|
|
#include <poll.h>
|
2021-05-23 00:30:29 +08:00
|
|
|
#include <sys/ioctl.h>
|
2012-11-22 16:43:40 +08:00
|
|
|
|
2021-12-07 16:05:01 +08:00
|
|
|
/**
|
|
|
|
* @brief This function will open a pipe.
|
|
|
|
*
|
|
|
|
* @param fd is the file descriptor.
|
|
|
|
*
|
|
|
|
* @return Return the operation status, 0 on successful.
|
|
|
|
* When the return value is -1, it means the file descriptor is invalid.
|
|
|
|
* When the return value is -RT_ENOMEM, it means insufficient memory allocation failed.
|
|
|
|
*/
|
2017-10-17 22:27:06 +08:00
|
|
|
static int pipe_fops_open(struct dfs_fd *fd)
|
2013-08-19 15:35:56 +08:00
|
|
|
{
|
2019-12-18 23:19:54 +08:00
|
|
|
int rc = 0;
|
2017-10-15 22:56:46 +08:00
|
|
|
rt_device_t device;
|
|
|
|
rt_pipe_t *pipe;
|
2013-08-19 15:35:56 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
pipe = (rt_pipe_t *)fd->data;
|
|
|
|
if (!pipe) return -1;
|
2013-08-19 15:35:56 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
device = &(pipe->parent);
|
|
|
|
rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
|
2013-08-19 15:35:56 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
if (device->ref_count == 0)
|
|
|
|
{
|
2017-12-29 22:33:39 +08:00
|
|
|
pipe->fifo = rt_ringbuffer_create(pipe->bufsz);
|
2019-12-18 21:38:05 +08:00
|
|
|
if (pipe->fifo == RT_NULL)
|
|
|
|
{
|
|
|
|
rc = -RT_ENOMEM;
|
|
|
|
goto __exit;
|
|
|
|
}
|
2017-10-15 22:56:46 +08:00
|
|
|
}
|
2013-08-19 15:35:56 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
switch (fd->flags & O_ACCMODE)
|
|
|
|
{
|
2021-01-01 17:21:48 +08:00
|
|
|
case O_RDONLY:
|
|
|
|
pipe->readers ++;
|
|
|
|
break;
|
|
|
|
case O_WRONLY:
|
|
|
|
pipe->writers ++;
|
|
|
|
break;
|
|
|
|
case O_RDWR:
|
|
|
|
pipe->readers ++;
|
|
|
|
pipe->writers ++;
|
|
|
|
break;
|
2013-08-19 15:35:56 +08:00
|
|
|
}
|
2017-10-15 22:56:46 +08:00
|
|
|
device->ref_count ++;
|
|
|
|
|
2019-12-18 21:38:05 +08:00
|
|
|
__exit:
|
2017-10-15 22:56:46 +08:00
|
|
|
rt_mutex_release(&(pipe->lock));
|
|
|
|
|
2019-12-18 21:38:05 +08:00
|
|
|
return rc;
|
2013-08-19 15:35:56 +08:00
|
|
|
}
|
|
|
|
|
2021-12-07 16:05:01 +08:00
|
|
|
/**
|
|
|
|
* @brief This function will close a pipe.
|
|
|
|
*
|
|
|
|
* @param fd is the file descriptor.
|
|
|
|
*
|
|
|
|
* @return Return the operation status, 0 on successful.
|
|
|
|
* When the return value is -1, it means the file descriptor is invalid.
|
|
|
|
*/
|
2017-10-17 22:27:06 +08:00
|
|
|
static int pipe_fops_close(struct dfs_fd *fd)
|
2012-11-22 16:43:40 +08:00
|
|
|
{
|
2017-10-15 22:56:46 +08:00
|
|
|
rt_device_t device;
|
|
|
|
rt_pipe_t *pipe;
|
2012-11-22 16:43:40 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
pipe = (rt_pipe_t *)fd->data;
|
|
|
|
if (!pipe) return -1;
|
2012-11-22 16:43:40 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
device = &(pipe->parent);
|
|
|
|
rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
|
|
|
|
|
|
|
|
switch (fd->flags & O_ACCMODE)
|
2013-08-19 15:35:56 +08:00
|
|
|
{
|
2021-01-01 17:21:48 +08:00
|
|
|
case O_RDONLY:
|
|
|
|
pipe->readers --;
|
|
|
|
break;
|
|
|
|
case O_WRONLY:
|
|
|
|
pipe->writers --;
|
|
|
|
break;
|
|
|
|
case O_RDWR:
|
|
|
|
pipe->readers --;
|
|
|
|
pipe->writers --;
|
|
|
|
break;
|
2017-10-15 22:56:46 +08:00
|
|
|
}
|
2013-08-19 15:35:56 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
if (pipe->writers == 0)
|
|
|
|
{
|
|
|
|
rt_wqueue_wakeup(&(pipe->reader_queue), (void*)(POLLIN | POLLERR | POLLHUP));
|
|
|
|
}
|
2013-08-19 15:35:56 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
if (pipe->readers == 0)
|
|
|
|
{
|
|
|
|
rt_wqueue_wakeup(&(pipe->writer_queue), (void*)(POLLOUT | POLLERR | POLLHUP));
|
|
|
|
}
|
2013-08-19 15:35:56 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
if (device->ref_count == 1)
|
|
|
|
{
|
2019-12-18 21:38:05 +08:00
|
|
|
if (pipe->fifo != RT_NULL)
|
|
|
|
rt_ringbuffer_destroy(pipe->fifo);
|
2017-10-15 22:56:46 +08:00
|
|
|
pipe->fifo = RT_NULL;
|
2013-08-19 15:35:56 +08:00
|
|
|
}
|
2017-10-15 22:56:46 +08:00
|
|
|
device->ref_count --;
|
|
|
|
|
|
|
|
rt_mutex_release(&(pipe->lock));
|
|
|
|
|
2019-03-31 15:21:49 +08:00
|
|
|
if (device->ref_count == 0 && pipe->is_named == RT_FALSE)
|
|
|
|
{
|
|
|
|
/* delete the unamed pipe */
|
|
|
|
rt_pipe_delete(device->parent.name);
|
|
|
|
}
|
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-12-07 16:05:01 +08:00
|
|
|
/**
|
|
|
|
* @brief This function will get the pipe space size depends on the command.
|
|
|
|
*
|
|
|
|
* @param fd is the file descriptor.
|
|
|
|
*
|
|
|
|
* @param cmd is the command. It determines what data will get.
|
|
|
|
*
|
|
|
|
* FIONREAD The command to get the number of bytes in the pipe.
|
|
|
|
*
|
|
|
|
* FIONWRITE The command to get the number of bytes can be written to the pipe.
|
|
|
|
*
|
|
|
|
* @param args is the pointer to the data to store the read data.
|
|
|
|
*
|
|
|
|
* @return Return the operation status, 0 on successful.
|
|
|
|
* When the return value is -EINVAL, it means the command is invalid.
|
|
|
|
*/
|
2017-10-17 22:27:06 +08:00
|
|
|
static int pipe_fops_ioctl(struct dfs_fd *fd, int cmd, void *args)
|
2017-10-15 22:56:46 +08:00
|
|
|
{
|
|
|
|
rt_pipe_t *pipe;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
pipe = (rt_pipe_t *)fd->data;
|
|
|
|
|
|
|
|
switch (cmd)
|
|
|
|
{
|
2021-01-01 17:21:48 +08:00
|
|
|
case FIONREAD:
|
|
|
|
*((int*)args) = rt_ringbuffer_data_len(pipe->fifo);
|
|
|
|
break;
|
|
|
|
case FIONWRITE:
|
|
|
|
*((int*)args) = rt_ringbuffer_space_len(pipe->fifo);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ret = -EINVAL;
|
|
|
|
break;
|
2017-10-15 22:56:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-12-07 16:05:01 +08:00
|
|
|
/**
|
|
|
|
* @brief This function will read data from pipe.
|
|
|
|
*
|
|
|
|
* @param fd is the file descriptor.
|
|
|
|
*
|
|
|
|
* @param buf is the buffer to store the read data.
|
|
|
|
*
|
|
|
|
* @param count is the length of data to be read.
|
|
|
|
*
|
|
|
|
* @return Return the length of data read.
|
|
|
|
* When the return value is 0, it means O_NONBLOCK is enabled and there is no thread that has the pipe open for writing.
|
|
|
|
* When the return value is -EAGAIN, it means there are no data to be read.
|
|
|
|
*/
|
2017-10-17 22:27:06 +08:00
|
|
|
static int pipe_fops_read(struct dfs_fd *fd, void *buf, size_t count)
|
2017-10-15 22:56:46 +08:00
|
|
|
{
|
|
|
|
int len = 0;
|
|
|
|
rt_pipe_t *pipe;
|
2013-08-19 15:35:56 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
pipe = (rt_pipe_t *)fd->data;
|
2012-11-22 16:43:40 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
/* no process has the pipe open for writing, return end-of-file */
|
|
|
|
if (pipe->writers == 0)
|
|
|
|
return 0;
|
2012-11-22 16:43:40 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
if (pipe->writers == 0)
|
2012-11-22 16:43:40 +08:00
|
|
|
{
|
2017-10-15 22:56:46 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = rt_ringbuffer_get(pipe->fifo, buf, count);
|
2012-11-22 16:43:40 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
if (len > 0)
|
|
|
|
{
|
|
|
|
break;
|
2012-11-22 16:43:40 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-10-15 22:56:46 +08:00
|
|
|
if (fd->flags & O_NONBLOCK)
|
|
|
|
{
|
|
|
|
len = -EAGAIN;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
rt_mutex_release(&pipe->lock);
|
|
|
|
rt_wqueue_wakeup(&(pipe->writer_queue), (void*)POLLOUT);
|
|
|
|
rt_wqueue_wait(&(pipe->reader_queue), 0, -1);
|
|
|
|
rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
|
2012-11-22 16:43:40 +08:00
|
|
|
}
|
2017-10-15 22:56:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* wakeup writer */
|
|
|
|
rt_wqueue_wakeup(&(pipe->writer_queue), (void*)POLLOUT);
|
2012-11-22 16:43:40 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
out:
|
|
|
|
rt_mutex_release(&pipe->lock);
|
|
|
|
return len;
|
2012-11-22 16:43:40 +08:00
|
|
|
}
|
|
|
|
|
2021-12-07 16:05:01 +08:00
|
|
|
/**
|
|
|
|
* @brief This function will write data to pipe.
|
|
|
|
*
|
|
|
|
* @param fd is the file descriptor.
|
|
|
|
*
|
|
|
|
* @param buf is a pointer to the data buffer to be written.
|
|
|
|
*
|
|
|
|
* @param count is the length of data to be write.
|
|
|
|
*
|
|
|
|
* @return Return the length of data written.
|
|
|
|
* When the return value is -EAGAIN, it means O_NONBLOCK is enabled and there are no space to be written.
|
|
|
|
* When the return value is -EPIPE, it means there is no thread that has the pipe open for reading.
|
|
|
|
*/
|
2017-10-17 22:27:06 +08:00
|
|
|
static int pipe_fops_write(struct dfs_fd *fd, const void *buf, size_t count)
|
2013-08-19 15:35:56 +08:00
|
|
|
{
|
2017-10-15 22:56:46 +08:00
|
|
|
int len;
|
|
|
|
rt_pipe_t *pipe;
|
|
|
|
int wakeup = 0;
|
|
|
|
int ret = 0;
|
|
|
|
uint8_t *pbuf;
|
|
|
|
|
|
|
|
pipe = (rt_pipe_t *)fd->data;
|
2013-08-19 15:57:59 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
if (pipe->readers == 0)
|
2013-08-19 15:35:56 +08:00
|
|
|
{
|
2017-10-15 22:56:46 +08:00
|
|
|
ret = -EPIPE;
|
|
|
|
goto out;
|
|
|
|
}
|
2013-08-19 15:35:56 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
if (count == 0)
|
|
|
|
return 0;
|
2013-08-19 15:35:56 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
pbuf = (uint8_t*)buf;
|
|
|
|
rt_mutex_take(&pipe->lock, -1);
|
2013-08-19 15:35:56 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
if (pipe->readers == 0)
|
|
|
|
{
|
|
|
|
if (ret == 0)
|
|
|
|
ret = -EPIPE;
|
|
|
|
break;
|
|
|
|
}
|
2013-08-19 15:35:56 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
len = rt_ringbuffer_put(pipe->fifo, pbuf, count - ret);
|
|
|
|
ret += len;
|
|
|
|
pbuf += len;
|
|
|
|
wakeup = 1;
|
2013-08-19 15:35:56 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
if (ret == count)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (fd->flags & O_NONBLOCK)
|
|
|
|
{
|
|
|
|
if (ret == 0)
|
|
|
|
{
|
|
|
|
ret = -EAGAIN;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-11-22 16:43:40 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
rt_mutex_release(&pipe->lock);
|
|
|
|
rt_wqueue_wakeup(&(pipe->reader_queue), (void*)POLLIN);
|
|
|
|
/* pipe full, waiting on suspended write list */
|
|
|
|
rt_wqueue_wait(&(pipe->writer_queue), 0, -1);
|
|
|
|
rt_mutex_take(&pipe->lock, -1);
|
|
|
|
}
|
|
|
|
rt_mutex_release(&pipe->lock);
|
2017-12-29 22:33:39 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
if (wakeup)
|
2013-08-19 15:35:56 +08:00
|
|
|
{
|
2017-10-15 22:56:46 +08:00
|
|
|
rt_wqueue_wakeup(&(pipe->reader_queue), (void*)POLLIN);
|
|
|
|
}
|
2013-08-19 15:35:56 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
2013-08-19 15:35:56 +08:00
|
|
|
|
2021-12-07 16:05:01 +08:00
|
|
|
/**
|
|
|
|
* @brief This function will get the pipe status.
|
|
|
|
*
|
|
|
|
* @param fd is the file descriptor.
|
|
|
|
*
|
|
|
|
* @param req is the request type.
|
|
|
|
*
|
|
|
|
* @return mask of the pipe status.
|
|
|
|
* POLLIN means there is data to be read.
|
|
|
|
* POLLHUP means there is no thread that has the pipe open for writing.
|
|
|
|
* POLLOUT means there is space to be written.
|
|
|
|
* POLLERR means there is no thread that has the pipe open for reading.
|
|
|
|
*/
|
2017-10-17 22:27:06 +08:00
|
|
|
static int pipe_fops_poll(struct dfs_fd *fd, rt_pollreq_t *req)
|
2017-10-15 22:56:46 +08:00
|
|
|
{
|
|
|
|
int mask = 0;
|
|
|
|
rt_pipe_t *pipe;
|
|
|
|
int mode = 0;
|
|
|
|
pipe = (rt_pipe_t *)fd->data;
|
2013-08-19 15:35:56 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
rt_poll_add(&(pipe->reader_queue), req);
|
|
|
|
rt_poll_add(&(pipe->writer_queue), req);
|
2013-08-19 15:35:56 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
switch (fd->flags & O_ACCMODE)
|
|
|
|
{
|
|
|
|
case O_RDONLY:
|
|
|
|
mode = 1;
|
|
|
|
break;
|
|
|
|
case O_WRONLY:
|
|
|
|
mode = 2;
|
|
|
|
break;
|
|
|
|
case O_RDWR:
|
|
|
|
mode = 3;
|
|
|
|
break;
|
|
|
|
}
|
2012-11-22 16:43:40 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
if (mode & 1)
|
|
|
|
{
|
|
|
|
if (rt_ringbuffer_data_len(pipe->fifo) != 0)
|
|
|
|
{
|
|
|
|
mask |= POLLIN;
|
|
|
|
}
|
|
|
|
if (pipe->writers == 0)
|
|
|
|
{
|
|
|
|
mask |= POLLHUP;
|
|
|
|
}
|
|
|
|
}
|
2012-11-22 16:43:40 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
if (mode & 2)
|
|
|
|
{
|
|
|
|
if (rt_ringbuffer_space_len(pipe->fifo) != 0)
|
2012-11-22 16:43:40 +08:00
|
|
|
{
|
2017-10-15 22:56:46 +08:00
|
|
|
mask |= POLLOUT;
|
2012-11-22 16:43:40 +08:00
|
|
|
}
|
2017-10-15 22:56:46 +08:00
|
|
|
if (pipe->readers == 0)
|
2012-11-22 16:43:40 +08:00
|
|
|
{
|
2017-10-15 22:56:46 +08:00
|
|
|
mask |= POLLERR;
|
2012-11-22 16:43:40 +08:00
|
|
|
}
|
2017-10-15 22:56:46 +08:00
|
|
|
}
|
2012-11-22 16:43:40 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
return mask;
|
2012-11-22 16:43:40 +08:00
|
|
|
}
|
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
static const struct dfs_file_ops pipe_fops =
|
2012-11-22 16:43:40 +08:00
|
|
|
{
|
2017-10-17 22:27:06 +08:00
|
|
|
pipe_fops_open,
|
|
|
|
pipe_fops_close,
|
|
|
|
pipe_fops_ioctl,
|
|
|
|
pipe_fops_read,
|
|
|
|
pipe_fops_write,
|
2017-10-15 22:56:46 +08:00
|
|
|
RT_NULL,
|
|
|
|
RT_NULL,
|
|
|
|
RT_NULL,
|
2017-10-17 22:27:06 +08:00
|
|
|
pipe_fops_poll,
|
2017-10-15 22:56:46 +08:00
|
|
|
};
|
2021-11-24 22:14:46 +08:00
|
|
|
#endif /* RT_USING_POSIX_DEVIO */
|
2017-12-29 22:33:39 +08:00
|
|
|
|
2021-12-07 16:05:01 +08:00
|
|
|
/**
|
|
|
|
* @brief This function will open the pipe and actually creates the pipe buffer.
|
|
|
|
*
|
|
|
|
* @param device is a pointer to the pipe device descriptor.
|
|
|
|
*
|
|
|
|
* @param oflag is the open method, but it is not used yet.
|
|
|
|
*
|
|
|
|
* @return Return the operation status.
|
|
|
|
* When the return value is RT_EOK, the operation is successful.
|
|
|
|
* When the return value is -RT_EINVAL, it means the device handle is empty.
|
|
|
|
* When the return value is -RT_ENOMEM, it means insufficient memory allocation failed.
|
|
|
|
*/
|
2021-03-27 11:54:46 +08:00
|
|
|
rt_err_t rt_pipe_open(rt_device_t device, rt_uint16_t oflag)
|
2017-12-29 22:33:39 +08:00
|
|
|
{
|
|
|
|
rt_pipe_t *pipe = (rt_pipe_t *)device;
|
2020-04-13 07:20:29 +08:00
|
|
|
rt_err_t ret = RT_EOK;
|
2017-12-29 22:33:39 +08:00
|
|
|
|
2020-04-13 07:20:29 +08:00
|
|
|
if (device == RT_NULL)
|
|
|
|
{
|
|
|
|
ret = -RT_EINVAL;
|
|
|
|
goto __exit;
|
|
|
|
}
|
2021-03-08 18:19:04 +08:00
|
|
|
|
2017-12-29 22:33:39 +08:00
|
|
|
rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
|
|
|
|
|
|
|
|
if (pipe->fifo == RT_NULL)
|
|
|
|
{
|
|
|
|
pipe->fifo = rt_ringbuffer_create(pipe->bufsz);
|
2020-04-12 11:58:33 +08:00
|
|
|
if (pipe->fifo == RT_NULL)
|
|
|
|
{
|
2020-04-13 07:20:29 +08:00
|
|
|
ret = -RT_ENOMEM;
|
2020-04-12 11:58:33 +08:00
|
|
|
}
|
2017-12-29 22:33:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
rt_mutex_release(&(pipe->lock));
|
|
|
|
|
2020-04-13 07:20:29 +08:00
|
|
|
__exit:
|
|
|
|
return ret;
|
2017-12-29 22:33:39 +08:00
|
|
|
}
|
|
|
|
|
2021-12-07 16:05:01 +08:00
|
|
|
/**
|
|
|
|
* @brief This function will close the pipe and release the pipe buffer.
|
|
|
|
*
|
|
|
|
* @param device is a pointer to the pipe device descriptor.
|
|
|
|
*
|
|
|
|
* @return Return the operation status.
|
|
|
|
* When the return value is RT_EOK, the operation is successful.
|
|
|
|
* When the return value is -RT_EINVAL, it means the device handle is empty.
|
|
|
|
*/
|
2021-03-27 11:54:46 +08:00
|
|
|
rt_err_t rt_pipe_close(rt_device_t device)
|
2017-12-29 22:33:39 +08:00
|
|
|
{
|
|
|
|
rt_pipe_t *pipe = (rt_pipe_t *)device;
|
|
|
|
|
|
|
|
if (device == RT_NULL) return -RT_EINVAL;
|
|
|
|
rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
|
|
|
|
|
|
|
|
if (device->ref_count == 1)
|
|
|
|
{
|
|
|
|
rt_ringbuffer_destroy(pipe->fifo);
|
|
|
|
pipe->fifo = RT_NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rt_mutex_release(&(pipe->lock));
|
|
|
|
|
|
|
|
return RT_EOK;
|
|
|
|
}
|
2017-10-15 22:56:46 +08:00
|
|
|
|
2021-12-07 16:05:01 +08:00
|
|
|
/**
|
|
|
|
* @brief This function will read the specified length of data from the pipe.
|
|
|
|
*
|
|
|
|
* @param device is a pointer to the pipe device descriptor.
|
|
|
|
*
|
|
|
|
* @param pos is a parameter compatible with POSIX standard interface (currently meaningless, just pass in 0).
|
|
|
|
*
|
|
|
|
* @param buffer is a pointer to the buffer to store the read data.
|
|
|
|
*
|
|
|
|
* @param count is the length of data to be read.
|
|
|
|
*
|
|
|
|
* @return Return the length of data read.
|
|
|
|
* When the return value is 0, it means the pipe device handle is empty or the count is 0.
|
|
|
|
*/
|
2021-03-27 11:54:46 +08:00
|
|
|
rt_size_t rt_pipe_read(rt_device_t device, rt_off_t pos, void *buffer, rt_size_t count)
|
2017-12-29 22:33:39 +08:00
|
|
|
{
|
|
|
|
uint8_t *pbuf;
|
2018-04-09 11:58:11 +08:00
|
|
|
rt_size_t read_bytes = 0;
|
2017-12-29 22:33:39 +08:00
|
|
|
rt_pipe_t *pipe = (rt_pipe_t *)device;
|
|
|
|
|
2017-12-31 14:45:43 +08:00
|
|
|
if (device == RT_NULL)
|
|
|
|
{
|
2021-06-12 18:11:51 +08:00
|
|
|
rt_set_errno(EINVAL);
|
2017-12-31 14:45:43 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2017-12-29 22:33:39 +08:00
|
|
|
if (count == 0) return 0;
|
|
|
|
|
|
|
|
pbuf = (uint8_t*)buffer;
|
|
|
|
rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
|
|
|
|
|
|
|
|
while (read_bytes < count)
|
|
|
|
{
|
|
|
|
int len = rt_ringbuffer_get(pipe->fifo, &pbuf[read_bytes], count - read_bytes);
|
|
|
|
if (len <= 0) break;
|
|
|
|
|
|
|
|
read_bytes += len;
|
|
|
|
}
|
|
|
|
rt_mutex_release(&pipe->lock);
|
|
|
|
|
|
|
|
return read_bytes;
|
|
|
|
}
|
|
|
|
|
2021-12-07 16:05:01 +08:00
|
|
|
/**
|
|
|
|
* @brief This function will write the specified length of data to the pipe.
|
|
|
|
*
|
|
|
|
* @param device is a pointer to the pipe device descriptor.
|
|
|
|
*
|
|
|
|
* @param pos is a parameter compatible with POSIX standard interface (currently meaningless, just pass in 0).
|
|
|
|
*
|
|
|
|
* @param buffer is a pointer to the data buffer to be written.
|
|
|
|
*
|
|
|
|
* @param count is the length of data to be written.
|
|
|
|
*
|
|
|
|
* @return Return the length of data written.
|
|
|
|
* When the return value is 0, it means the pipe device handle is empty or the count is 0.
|
|
|
|
*/
|
2021-03-27 11:54:46 +08:00
|
|
|
rt_size_t rt_pipe_write(rt_device_t device, rt_off_t pos, const void *buffer, rt_size_t count)
|
2017-12-29 22:33:39 +08:00
|
|
|
{
|
|
|
|
uint8_t *pbuf;
|
2018-04-09 11:58:11 +08:00
|
|
|
rt_size_t write_bytes = 0;
|
2017-12-29 22:33:39 +08:00
|
|
|
rt_pipe_t *pipe = (rt_pipe_t *)device;
|
|
|
|
|
2017-12-31 14:45:43 +08:00
|
|
|
if (device == RT_NULL)
|
|
|
|
{
|
2021-06-12 18:11:51 +08:00
|
|
|
rt_set_errno(EINVAL);
|
2017-12-31 14:45:43 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2017-12-29 22:33:39 +08:00
|
|
|
if (count == 0) return 0;
|
|
|
|
|
|
|
|
pbuf = (uint8_t*)buffer;
|
|
|
|
rt_mutex_take(&pipe->lock, -1);
|
|
|
|
|
|
|
|
while (write_bytes < count)
|
|
|
|
{
|
|
|
|
int len = rt_ringbuffer_put(pipe->fifo, &pbuf[write_bytes], count - write_bytes);
|
|
|
|
if (len <= 0) break;
|
|
|
|
|
|
|
|
write_bytes += len;
|
|
|
|
}
|
|
|
|
rt_mutex_release(&pipe->lock);
|
|
|
|
|
|
|
|
return write_bytes;
|
|
|
|
}
|
|
|
|
|
2021-12-07 16:05:01 +08:00
|
|
|
/**
|
|
|
|
* @brief This function is not used yet.
|
|
|
|
*
|
|
|
|
* @param dev is not used yet.
|
|
|
|
*
|
|
|
|
* @param cmd is not used yet.
|
|
|
|
*
|
|
|
|
* @param args is not used yet.
|
|
|
|
*
|
|
|
|
* @return Always return RT_EOK yet.
|
|
|
|
*/
|
2017-12-29 22:33:39 +08:00
|
|
|
rt_err_t rt_pipe_control(rt_device_t dev, int cmd, void *args)
|
|
|
|
{
|
|
|
|
return RT_EOK;
|
|
|
|
}
|
|
|
|
|
2018-06-10 17:59:17 +08:00
|
|
|
#ifdef RT_USING_DEVICE_OPS
|
2021-03-08 18:19:04 +08:00
|
|
|
const static struct rt_device_ops pipe_ops =
|
2018-06-10 17:59:17 +08:00
|
|
|
{
|
|
|
|
RT_NULL,
|
|
|
|
rt_pipe_open,
|
|
|
|
rt_pipe_close,
|
|
|
|
rt_pipe_read,
|
|
|
|
rt_pipe_write,
|
|
|
|
rt_pipe_control,
|
|
|
|
};
|
2021-12-01 07:03:48 +08:00
|
|
|
#endif /* RT_USING_DEVICE_OPS */
|
2018-06-10 17:59:17 +08:00
|
|
|
|
2021-12-07 16:05:01 +08:00
|
|
|
/**
|
|
|
|
* @brief This function will initialize a pipe device.
|
|
|
|
* The system allocates a pipe handle from dynamic heap memory, initializes the pipe handle
|
|
|
|
* with the specified value, and registers the pipe device with the system.
|
|
|
|
*
|
|
|
|
* @param name is the name of pipe device.
|
|
|
|
*
|
|
|
|
* @param bufsz is the size of pipe buffer.
|
|
|
|
*
|
|
|
|
* @return Return the pointer to the pipe device.
|
|
|
|
* When the return value is RT_NULL, it means the initialization failed.
|
|
|
|
*/
|
2017-12-29 22:33:39 +08:00
|
|
|
rt_pipe_t *rt_pipe_create(const char *name, int bufsz)
|
2013-08-19 12:24:15 +08:00
|
|
|
{
|
2017-10-15 22:56:46 +08:00
|
|
|
rt_pipe_t *pipe;
|
|
|
|
rt_device_t dev;
|
2013-08-19 12:24:15 +08:00
|
|
|
|
2019-06-18 20:09:19 +08:00
|
|
|
pipe = (rt_pipe_t *)rt_malloc(sizeof(rt_pipe_t));
|
2017-10-15 22:56:46 +08:00
|
|
|
if (pipe == RT_NULL) return RT_NULL;
|
2013-08-19 12:24:15 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
rt_memset(pipe, 0, sizeof(rt_pipe_t));
|
2019-03-31 15:21:49 +08:00
|
|
|
pipe->is_named = RT_TRUE; /* initialize as a named pipe */
|
2021-11-18 04:57:15 +08:00
|
|
|
rt_mutex_init(&(pipe->lock), name, RT_IPC_FLAG_PRIO);
|
2018-06-26 12:02:03 +08:00
|
|
|
rt_wqueue_init(&(pipe->reader_queue));
|
|
|
|
rt_wqueue_init(&(pipe->writer_queue));
|
2013-08-19 12:24:15 +08:00
|
|
|
|
2017-12-29 22:33:39 +08:00
|
|
|
RT_ASSERT(bufsz < 0xFFFF);
|
|
|
|
pipe->bufsz = bufsz;
|
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
dev = &(pipe->parent);
|
|
|
|
dev->type = RT_Device_Class_Pipe;
|
2018-06-10 17:59:17 +08:00
|
|
|
#ifdef RT_USING_DEVICE_OPS
|
|
|
|
dev->ops = &pipe_ops;
|
|
|
|
#else
|
2017-12-29 22:33:39 +08:00
|
|
|
dev->init = RT_NULL;
|
|
|
|
dev->open = rt_pipe_open;
|
|
|
|
dev->read = rt_pipe_read;
|
|
|
|
dev->write = rt_pipe_write;
|
|
|
|
dev->close = rt_pipe_close;
|
|
|
|
dev->control = rt_pipe_control;
|
2018-06-10 17:59:17 +08:00
|
|
|
#endif
|
2017-12-29 22:33:39 +08:00
|
|
|
|
|
|
|
dev->rx_indicate = RT_NULL;
|
|
|
|
dev->tx_complete = RT_NULL;
|
2013-08-19 15:35:56 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
if (rt_device_register(&(pipe->parent), name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE) != 0)
|
|
|
|
{
|
|
|
|
rt_free(pipe);
|
|
|
|
return RT_NULL;
|
|
|
|
}
|
2021-11-24 22:14:46 +08:00
|
|
|
#ifdef RT_USING_POSIX_DEVIO
|
2017-10-15 22:56:46 +08:00
|
|
|
dev->fops = (void*)&pipe_fops;
|
2021-12-01 07:03:48 +08:00
|
|
|
#endif /* RT_USING_POSIX_DEVIO */
|
2013-08-19 12:24:15 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
return pipe;
|
2013-08-19 12:24:15 +08:00
|
|
|
}
|
|
|
|
|
2021-12-07 16:05:01 +08:00
|
|
|
/**
|
|
|
|
* @brief This function will delete a pipe device.
|
|
|
|
* The system will release the pipe handle and unregister the pipe device from the system.
|
|
|
|
*
|
|
|
|
* @param pipe is the pointer to the pipe device.
|
|
|
|
*
|
|
|
|
* @return Return the operation status, 0 on successful.
|
|
|
|
* When the return value is -RT_EINVAL, it means the pipe device is not found or the device isn't a pipe.
|
|
|
|
* When the return value is -RT_EBUSY, it means the pipe device is busy.
|
|
|
|
*/
|
2017-10-15 22:56:46 +08:00
|
|
|
int rt_pipe_delete(const char *name)
|
2013-08-19 12:24:15 +08:00
|
|
|
{
|
2017-10-15 22:56:46 +08:00
|
|
|
int result = 0;
|
|
|
|
rt_device_t device;
|
|
|
|
|
|
|
|
device = rt_device_find(name);
|
|
|
|
if (device)
|
|
|
|
{
|
|
|
|
if (device->type == RT_Device_Class_Pipe)
|
|
|
|
{
|
|
|
|
rt_pipe_t *pipe;
|
|
|
|
|
|
|
|
if (device->ref_count != 0)
|
|
|
|
{
|
|
|
|
return -RT_EBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
pipe = (rt_pipe_t *)device;
|
|
|
|
|
|
|
|
rt_mutex_detach(&(pipe->lock));
|
|
|
|
rt_device_unregister(device);
|
|
|
|
|
2017-12-29 22:33:39 +08:00
|
|
|
/* close fifo ringbuffer */
|
2021-03-08 18:19:04 +08:00
|
|
|
if (pipe->fifo)
|
2017-12-29 22:33:39 +08:00
|
|
|
{
|
|
|
|
rt_ringbuffer_destroy(pipe->fifo);
|
|
|
|
pipe->fifo = RT_NULL;
|
|
|
|
}
|
2017-10-15 22:56:46 +08:00
|
|
|
rt_free(pipe);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-06-12 18:11:51 +08:00
|
|
|
result = -RT_EINVAL;
|
2017-10-15 22:56:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-06-12 18:11:51 +08:00
|
|
|
result = -RT_EINVAL;
|
2017-10-15 22:56:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
2013-08-19 12:24:15 +08:00
|
|
|
}
|
|
|
|
|
2021-11-24 22:14:46 +08:00
|
|
|
#ifdef RT_USING_POSIX_DEVIO
|
2021-12-07 16:05:01 +08:00
|
|
|
/**
|
|
|
|
* @brief This function will creat a anonymous pipe.
|
|
|
|
*
|
|
|
|
* @param fildes[0] is the read handle.
|
|
|
|
* fildes[1] is the write handle.
|
|
|
|
*
|
|
|
|
* @return Return the operation status, 0 on successful, -1 on failed.
|
|
|
|
*/
|
2017-10-15 22:56:46 +08:00
|
|
|
int pipe(int fildes[2])
|
2012-11-22 16:43:40 +08:00
|
|
|
{
|
2017-10-15 22:56:46 +08:00
|
|
|
rt_pipe_t *pipe;
|
2021-03-27 11:54:46 +08:00
|
|
|
char dname[RT_NAME_MAX];
|
|
|
|
char dev_name[RT_NAME_MAX * 4];
|
2017-10-15 22:56:46 +08:00
|
|
|
static int pipeno = 0;
|
2012-11-22 16:43:40 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
rt_snprintf(dname, sizeof(dname), "pipe%d", pipeno++);
|
|
|
|
|
2017-12-29 22:33:39 +08:00
|
|
|
pipe = rt_pipe_create(dname, PIPE_BUFSZ);
|
2013-08-19 12:24:15 +08:00
|
|
|
if (pipe == RT_NULL)
|
2017-10-15 22:56:46 +08:00
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2012-11-22 16:43:40 +08:00
|
|
|
|
2019-03-31 15:21:49 +08:00
|
|
|
pipe->is_named = RT_FALSE; /* unamed pipe */
|
2017-10-15 22:56:46 +08:00
|
|
|
rt_snprintf(dev_name, sizeof(dev_name), "/dev/%s", dname);
|
|
|
|
fildes[0] = open(dev_name, O_RDONLY, 0);
|
|
|
|
if (fildes[0] < 0)
|
2013-08-19 12:24:15 +08:00
|
|
|
{
|
2017-10-15 22:56:46 +08:00
|
|
|
return -1;
|
2013-08-19 12:24:15 +08:00
|
|
|
}
|
2012-11-22 16:43:40 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
fildes[1] = open(dev_name, O_WRONLY, 0);
|
|
|
|
if (fildes[1] < 0)
|
|
|
|
{
|
2018-08-11 18:45:18 +08:00
|
|
|
close(fildes[0]);
|
2017-10-15 22:56:46 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2012-11-22 16:43:40 +08:00
|
|
|
}
|
|
|
|
|
2021-12-07 16:05:01 +08:00
|
|
|
/**
|
|
|
|
* @brief This function will create a named pipe.
|
|
|
|
*
|
|
|
|
* @param path is the name of pipe device.
|
|
|
|
*
|
|
|
|
* @param mode is not used yet.
|
|
|
|
*
|
|
|
|
* @return Return the operation status, 0 on successful, -1 on failed.
|
|
|
|
*/
|
2017-10-15 22:56:46 +08:00
|
|
|
int mkfifo(const char *path, mode_t mode)
|
2012-11-22 16:43:40 +08:00
|
|
|
{
|
2017-10-15 22:56:46 +08:00
|
|
|
rt_pipe_t *pipe;
|
2021-03-08 18:19:04 +08:00
|
|
|
|
2017-12-29 22:33:39 +08:00
|
|
|
pipe = rt_pipe_create(path, PIPE_BUFSZ);
|
2012-11-22 16:43:40 +08:00
|
|
|
if (pipe == RT_NULL)
|
2017-10-15 22:56:46 +08:00
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2012-11-22 16:43:40 +08:00
|
|
|
|
2017-10-15 22:56:46 +08:00
|
|
|
return 0;
|
2012-11-22 16:43:40 +08:00
|
|
|
}
|
2021-11-24 22:14:46 +08:00
|
|
|
#endif /* RT_USING_POSIX_DEVIO */
|