• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * drivers/pipes/pipe.c
3  *
4  *   Copyright (C) 2008-2009, 2015, 2018 Gregory Nutt. All rights reserved.
5  *   Author: Gregory Nutt <gnutt@nuttx.org>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name NuttX nor the names of its contributors may be
18  *    used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  ****************************************************************************/
35 
36 /****************************************************************************
37  * Included Files
38  ****************************************************************************/
39 #include "pipe_common.h"
40 #include <assert.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <semaphore.h>
44 #include <stdio.h>
45 #include <sys/types.h>
46 #include <unistd.h>
47 #include "fs/driver.h"
48 #include "los_init.h"
49 
50 #if CONFIG_DEV_PIPE_SIZE > 0
51 
52 /****************************************************************************
53  * Pre-processor Definitions
54  ****************************************************************************/
55 
56 #define MAX_PIPES 32
57 
58 /****************************************************************************
59  * Private Types
60  ****************************************************************************/
61 
62 /****************************************************************************
63  * Private Function Prototypes
64  ****************************************************************************/
65 
66 static int pipe_close(struct file *filep);
67 #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
68 int pipe_unlink(struct Vnode *priv);
69 #endif
70 
71 /****************************************************************************
72  * Private Data
73  ****************************************************************************/
74 
pipe_map(struct file * filep,LosVmMapRegion * region)75 static ssize_t pipe_map(struct file* filep, LosVmMapRegion *region)
76 {
77   PRINTK("%s %d, mmap is not support\n", __FUNCTION__, __LINE__);
78   return 0;
79 }
80 
81 static const struct file_operations_vfs pipe_fops =
82 {
83   .open = pipecommon_open,      /* open */
84   .close = pipe_close,          /* close */
85   .read = pipecommon_read,      /* read */
86   .write = pipecommon_write,    /* write */
87   .seek = NULL,                 /* seek */
88   .ioctl = NULL,                /* ioctl */
89   .mmap = pipe_map,             /* mmap */
90   .poll = pipecommon_poll,      /* poll */
91 #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
92   .unlink = pipe_unlink,        /* unlink */
93 #endif
94 };
95 
96 static sem_t  g_pipesem       = {NULL};
97 static uint32_t g_pipeset     = 0;
98 static uint32_t g_pipecreated = 0;
99 
100 /****************************************************************************
101  * Private Functions
102  ****************************************************************************/
103 
104 /****************************************************************************
105  * Name: pipe_allocate
106  ****************************************************************************/
107 
pipe_allocate(void)108 static inline int pipe_allocate(void)
109 {
110   int pipeno;
111   int ret = -ENFILE;
112 
113   for (pipeno = 0; pipeno < MAX_PIPES; pipeno++)
114     {
115       if ((g_pipeset & (1 << pipeno)) == 0)
116         {
117           g_pipeset |= (1 << pipeno);
118           ret = pipeno;
119           break;
120         }
121     }
122 
123   return ret;
124 }
125 
126 /****************************************************************************
127  * Name: pipe_free
128  ****************************************************************************/
129 
pipe_free(int pipeno)130 static inline void pipe_free(int pipeno)
131 {
132   int ret;
133 
134   ret = sem_wait(&g_pipesem);
135   if (ret == OK)
136     {
137       g_pipeset &= ~(1 << pipeno);
138       (void)sem_post(&g_pipesem);
139     }
140 }
141 
142 /****************************************************************************
143  * Name: pipe_close
144  ****************************************************************************/
145 
pipe_close(struct file * filep)146 static int pipe_close(struct file *filep)
147 {
148   struct Vnode *vnode    = filep->f_vnode;
149   struct pipe_dev_s *dev = (struct pipe_dev_s *)((struct drv_data *)vnode->data)->priv;
150   int ret;
151 
152   if (dev == NULL)
153     {
154       return -EINVAL;
155     }
156 
157   /* Perform common close operations */
158 
159   ret = pipecommon_close(filep);
160   if (ret == 0 && vnode->useCount <= 1)
161     {
162       /* Release the pipe when there are no further open references to it. */
163 
164       pipe_free(dev->d_pipeno);
165     }
166 
167   return ret;
168 }
169 
170 /****************************************************************************
171  * Name: pipe_unlink
172  ****************************************************************************/
173 
174 #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
pipe_unlink(struct Vnode * vnode)175  int pipe_unlink(struct Vnode *vnode)
176 {
177   struct pipe_dev_s *dev = ((struct drv_data *)vnode->data)->priv;
178   uint8_t pipeno = 0;
179   int ret;
180 
181   if (dev != NULL)
182     {
183         pipeno = dev->d_pipeno;
184     }
185   /* Perform common close operations */
186   ret = pipecommon_unlink(vnode);
187   if (ret == 0)
188     {
189       (void)sem_wait(&g_pipesem);
190       g_pipecreated &= ~(1 << pipeno);
191       (void)sem_post(&g_pipesem);
192       /* Release the pipe when there are no further open references to it. */
193       pipe_free(pipeno);
194     }
195   return ret;
196 }
197 #endif
198 
199 /****************************************************************************
200  * Public Functions
201  ****************************************************************************/
202 
203 /****************************************************************************
204  * Name: pipe2
205  *
206  * Description:
207  *   pipe() creates a pair of file descriptors, pointing to a pipe vnode,
208  *   and  places them in the array pointed to by 'fd'. fd[0] is for reading,
209  *   fd[1] is for writing.
210  *
211  *   NOTE: mkfifo2 is a special, non-standard, NuttX-only interface.  Since
212  *   the NuttX FIFOs are based in in-memory, circular buffers, the ability
213  *   to control the size of those buffers is critical for system tuning.
214  *
215  * Input Parameters:
216  *   fd[2] - The user provided array in which to catch the pipe file
217  *   descriptors
218  *   bufsize - The size of the in-memory, circular buffer in bytes.
219  *
220  * Returned Value:
221  *   0 is returned on success; otherwise, -1 is returned with errno set
222  *   appropriately.
223  *
224  ****************************************************************************/
225 
UpdateDev(struct pipe_dev_s * dev)226 static void UpdateDev(struct pipe_dev_s *dev)
227 {
228   int ret;
229   struct Vnode *vnode = NULL;
230   struct pipe_dev_s *olddev = NULL;
231   struct drv_data *data = NULL;
232 
233   VnodeHold();
234   ret = VnodeLookup(dev->name, &vnode, 0);
235   if (ret != 0)
236     {
237       VnodeDrop();
238       PRINT_ERR("[%s,%d] failed. err: %d\n", __FUNCTION__, __LINE__, ret);
239       return;
240     }
241   data = (struct drv_data *)vnode->data;
242   olddev = (struct pipe_dev_s *)data->priv;
243   if (olddev != NULL)
244     {
245       if (olddev->d_buffer != NULL)
246         {
247           free(olddev->d_buffer);
248           olddev->d_buffer = NULL;
249         }
250       pipecommon_freedev(olddev);
251     }
252   data->priv = dev;
253   VnodeDrop();
254   return;
255 }
256 
pipe(int fd[2])257 int pipe(int fd[2])
258 {
259   struct pipe_dev_s *dev = NULL;
260   char devname[16];
261   int pipeno;
262   int errcode;
263   int ret;
264   struct file *filep = NULL;
265   size_t bufsize = 1024;
266 
267   /* Get exclusive access to the pipe allocation data */
268 
269   ret = sem_wait(&g_pipesem);
270   if (ret < 0)
271     {
272       errcode = -ret;
273       goto errout;
274     }
275 
276   /* Allocate a minor number for the pipe device */
277 
278   pipeno = pipe_allocate();
279   if (pipeno < 0)
280     {
281       (void)sem_post(&g_pipesem);
282       errcode = -pipeno;
283       goto errout;
284     }
285 
286   /* Create a pathname to the pipe device */
287 
288   snprintf_s(devname, sizeof(devname), sizeof(devname) - 1, "/dev/pipe%d", pipeno);
289 
290   /* No.. Allocate and initialize a new device structure instance */
291 
292   dev = pipecommon_allocdev(bufsize, devname);
293   if (!dev)
294     {
295       (void)sem_post(&g_pipesem);
296       errcode = ENOMEM;
297       goto errout_with_pipe;
298     }
299 
300   dev->d_pipeno = pipeno;
301 
302   /* Check if the pipe device has already been created */
303 
304   if ((g_pipecreated & (1 << pipeno)) == 0)
305     {
306       /* Register the pipe device */
307 
308       ret = register_driver(devname, &pipe_fops, 0660, (void *)dev);
309       if (ret != 0)
310         {
311           (void)sem_post(&g_pipesem);
312           errcode = -ret;
313           goto errout_with_dev;
314         }
315 
316       /* Remember that we created this device */
317 
318        g_pipecreated |= (1 << pipeno);
319     }
320   else
321     {
322        UpdateDev(dev);
323     }
324   (void)sem_post(&g_pipesem);
325 
326   /* Get a write file descriptor */
327 
328   fd[1] = open(devname, O_WRONLY);
329   if (fd[1] < 0)
330     {
331       errcode = -fd[1];
332       goto errout_with_driver;
333     }
334 
335   /* Get a read file descriptor */
336 
337   fd[0] = open(devname, O_RDONLY);
338   if (fd[0] < 0)
339     {
340       errcode = -fd[0];
341       goto errout_with_wrfd;
342     }
343 
344   ret = fs_getfilep(fd[0], &filep);
345   filep->ops = &pipe_fops;
346 
347   ret = fs_getfilep(fd[1], &filep);
348   filep->ops = &pipe_fops;
349 
350   return OK;
351 
352 errout_with_wrfd:
353   close(fd[1]);
354 
355 errout_with_driver:
356   unregister_driver(devname);
357   (void)sem_wait(&g_pipesem);
358   g_pipecreated &= ~(1 << pipeno);
359   (void)sem_post(&g_pipesem);
360 
361 errout_with_dev:
362   if (dev)
363     {
364       pipecommon_freedev(dev);
365     }
366 
367 errout_with_pipe:
368   pipe_free(pipeno);
369 
370 errout:
371   set_errno(errcode);
372   return VFS_ERROR;
373 }
374 
pipe_init()375 int pipe_init()
376 {
377     int ret = sem_init(&g_pipesem, 0, 1);
378     if (ret != 0) {
379         dprintf("pipe_init failed!\n");
380     }
381     return ret;
382 }
383 
384 LOS_MODULE_INIT(pipe_init, LOS_INIT_LEVEL_KMOD_EXTENDED);
385 
386 #endif /* CONFIG_DEV_PIPE_SIZE > 0 */
387