• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * drivers/pipes/pipe.c
3  *
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.  The
7  * ASF licenses this file to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance with the
9  * License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
16  * License for the specific language governing permissions and limitations
17  * under the License.
18  *
19  ****************************************************************************/
20 
21 /****************************************************************************
22  * Included Files
23  ****************************************************************************/
24 #include "pipe_common.h"
25 #include <assert.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <semaphore.h>
29 #include <stdio.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 #include "fs/driver.h"
33 #include "los_init.h"
34 
35 #if CONFIG_DEV_PIPE_SIZE > 0
36 
37 /****************************************************************************
38  * Pre-processor Definitions
39  ****************************************************************************/
40 
41 #define MAX_PIPES 32
42 
43 /****************************************************************************
44  * Private Types
45  ****************************************************************************/
46 
47 /****************************************************************************
48  * Private Function Prototypes
49  ****************************************************************************/
50 
51 static int pipe_close(struct file *filep);
52 #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
53 int pipe_unlink(struct Vnode *priv);
54 #endif
55 
56 /****************************************************************************
57  * Private Data
58  ****************************************************************************/
59 
pipe_map(struct file * filep,LosVmMapRegion * region)60 static ssize_t pipe_map(struct file* filep, LosVmMapRegion *region)
61 {
62   PRINTK("%s %d, mmap is not support\n", __FUNCTION__, __LINE__);
63   return 0;
64 }
65 
66 static const struct file_operations_vfs pipe_fops =
67 {
68   .open = pipecommon_open,      /* open */
69   .close = pipe_close,          /* close */
70   .read = pipecommon_read,      /* read */
71   .write = pipecommon_write,    /* write */
72   .seek = NULL,                 /* seek */
73   .ioctl = NULL,                /* ioctl */
74   .mmap = pipe_map,             /* mmap */
75   .poll = pipecommon_poll,      /* poll */
76 #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
77   .unlink = pipe_unlink,        /* unlink */
78 #endif
79 };
80 
81 static sem_t  g_pipesem       = {NULL};
82 static uint32_t g_pipeset     = 0;
83 static uint32_t g_pipecreated = 0;
84 
85 /****************************************************************************
86  * Private Functions
87  ****************************************************************************/
88 
89 /****************************************************************************
90  * Name: pipe_allocate
91  ****************************************************************************/
92 
pipe_allocate(void)93 static inline int pipe_allocate(void)
94 {
95   int pipeno;
96   int ret = -ENFILE;
97 
98   for (pipeno = 0; pipeno < MAX_PIPES; pipeno++)
99     {
100       if ((g_pipeset & (1 << pipeno)) == 0)
101         {
102           g_pipeset |= (1 << pipeno);
103           ret = pipeno;
104           break;
105         }
106     }
107 
108   return ret;
109 }
110 
111 /****************************************************************************
112  * Name: pipe_free
113  ****************************************************************************/
114 
pipe_free(int pipeno)115 static inline void pipe_free(int pipeno)
116 {
117   int ret;
118 
119   ret = sem_wait(&g_pipesem);
120   if (ret == OK)
121     {
122       g_pipeset &= ~(1 << pipeno);
123       (void)sem_post(&g_pipesem);
124     }
125 }
126 
127 /****************************************************************************
128  * Name: pipe_close
129  ****************************************************************************/
130 
pipe_close(struct file * filep)131 static int pipe_close(struct file *filep)
132 {
133   struct Vnode *vnode    = filep->f_vnode;
134   struct pipe_dev_s *dev = (struct pipe_dev_s *)((struct drv_data *)vnode->data)->priv;
135   int ret;
136 
137   if (dev == NULL)
138     {
139       return -EINVAL;
140     }
141 
142   /* Perform common close operations */
143 
144   ret = pipecommon_close(filep);
145   if (ret == 0 && vnode->useCount <= 1)
146     {
147       /* Release the pipe when there are no further open references to it. */
148 
149       pipe_free(dev->d_pipeno);
150     }
151 
152   return ret;
153 }
154 
155 /****************************************************************************
156  * Name: pipe_unlink
157  ****************************************************************************/
158 
159 #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
pipe_unlink(struct Vnode * vnode)160  int pipe_unlink(struct Vnode *vnode)
161 {
162   struct pipe_dev_s *dev = ((struct drv_data *)vnode->data)->priv;
163   uint8_t pipeno = 0;
164   int ret;
165 
166   if (dev != NULL)
167     {
168         pipeno = dev->d_pipeno;
169     }
170   /* Perform common close operations */
171   ret = pipecommon_unlink(vnode);
172   if (ret == 0)
173     {
174       (void)sem_wait(&g_pipesem);
175       g_pipecreated &= ~(1 << pipeno);
176       (void)sem_post(&g_pipesem);
177       /* Release the pipe when there are no further open references to it. */
178       pipe_free(pipeno);
179     }
180   return ret;
181 }
182 #endif
183 
184 /****************************************************************************
185  * Public Functions
186  ****************************************************************************/
187 
188 /****************************************************************************
189  * Name: pipe2
190  *
191  * Description:
192  *   pipe() creates a pair of file descriptors, pointing to a pipe vnode,
193  *   and  places them in the array pointed to by 'fd'. fd[0] is for reading,
194  *   fd[1] is for writing.
195  *
196  *   NOTE: mkfifo2 is a special, non-standard, NuttX-only interface.  Since
197  *   the NuttX FIFOs are based in in-memory, circular buffers, the ability
198  *   to control the size of those buffers is critical for system tuning.
199  *
200  * Input Parameters:
201  *   fd[2] - The user provided array in which to catch the pipe file
202  *   descriptors
203  *   bufsize - The size of the in-memory, circular buffer in bytes.
204  *
205  * Returned Value:
206  *   0 is returned on success; otherwise, -1 is returned with errno set
207  *   appropriately.
208  *
209  ****************************************************************************/
210 
UpdateDev(struct pipe_dev_s * dev)211 static void UpdateDev(struct pipe_dev_s *dev)
212 {
213   int ret;
214   struct Vnode *vnode = NULL;
215   struct pipe_dev_s *olddev = NULL;
216   struct drv_data *data = NULL;
217 
218   VnodeHold();
219   ret = VnodeLookup(dev->name, &vnode, 0);
220   if (ret != 0)
221     {
222       VnodeDrop();
223       PRINT_ERR("[%s,%d] failed. err: %d\n", __FUNCTION__, __LINE__, ret);
224       return;
225     }
226   data = (struct drv_data *)vnode->data;
227   olddev = (struct pipe_dev_s *)data->priv;
228   if (olddev != NULL)
229     {
230       if (olddev->d_buffer != NULL)
231         {
232           free(olddev->d_buffer);
233           olddev->d_buffer = NULL;
234         }
235       pipecommon_freedev(olddev);
236     }
237   data->priv = dev;
238   VnodeDrop();
239   return;
240 }
241 
pipe(int fd[2])242 int pipe(int fd[2])
243 {
244   struct pipe_dev_s *dev = NULL;
245   char devname[16];
246   int pipeno;
247   int errcode;
248   int ret;
249   struct file *filep = NULL;
250   size_t bufsize = 1024;
251 
252   /* Get exclusive access to the pipe allocation data */
253 
254   ret = sem_wait(&g_pipesem);
255   if (ret < 0)
256     {
257       errcode = -ret;
258       goto errout;
259     }
260 
261   /* Allocate a minor number for the pipe device */
262 
263   pipeno = pipe_allocate();
264   if (pipeno < 0)
265     {
266       (void)sem_post(&g_pipesem);
267       errcode = -pipeno;
268       goto errout;
269     }
270 
271   /* Create a pathname to the pipe device */
272 
273   snprintf_s(devname, sizeof(devname), sizeof(devname) - 1, "/dev/pipe%d", pipeno);
274 
275   /* No.. Allocate and initialize a new device structure instance */
276 
277   dev = pipecommon_allocdev(bufsize, devname);
278   if (!dev)
279     {
280       (void)sem_post(&g_pipesem);
281       errcode = ENOMEM;
282       goto errout_with_pipe;
283     }
284 
285   dev->d_pipeno = pipeno;
286 
287   /* Check if the pipe device has already been created */
288 
289   if ((g_pipecreated & (1 << pipeno)) == 0)
290     {
291       /* Register the pipe device */
292 
293       ret = register_driver(devname, &pipe_fops, 0660, (void *)dev);
294       if (ret != 0)
295         {
296           (void)sem_post(&g_pipesem);
297           errcode = -ret;
298           goto errout_with_dev;
299         }
300 
301       /* Remember that we created this device */
302 
303        g_pipecreated |= (1 << pipeno);
304     }
305   else
306     {
307        UpdateDev(dev);
308     }
309   (void)sem_post(&g_pipesem);
310 
311   /* Get a write file descriptor */
312 
313   fd[1] = open(devname, O_WRONLY);
314   if (fd[1] < 0)
315     {
316       errcode = -fd[1];
317       goto errout_with_driver;
318     }
319 
320   /* Get a read file descriptor */
321 
322   fd[0] = open(devname, O_RDONLY);
323   if (fd[0] < 0)
324     {
325       errcode = -fd[0];
326       goto errout_with_wrfd;
327     }
328 
329   ret = fs_getfilep(fd[0], &filep);
330   filep->ops = &pipe_fops;
331 
332   ret = fs_getfilep(fd[1], &filep);
333   filep->ops = &pipe_fops;
334 
335   return OK;
336 
337 errout_with_wrfd:
338   close(fd[1]);
339 
340 errout_with_driver:
341   unregister_driver(devname);
342   (void)sem_wait(&g_pipesem);
343   g_pipecreated &= ~(1 << pipeno);
344   (void)sem_post(&g_pipesem);
345 
346 errout_with_dev:
347   if (dev)
348     {
349       pipecommon_freedev(dev);
350     }
351 
352 errout_with_pipe:
353   pipe_free(pipeno);
354 
355 errout:
356   set_errno(errcode);
357   return VFS_ERROR;
358 }
359 
pipe_init()360 int pipe_init()
361 {
362     int ret = sem_init(&g_pipesem, 0, 1);
363     if (ret != 0) {
364         dprintf("pipe_init failed!\n");
365     }
366     return ret;
367 }
368 
369 LOS_MODULE_INIT(pipe_init, LOS_INIT_LEVEL_KMOD_EXTENDED);
370 
371 #endif /* CONFIG_DEV_PIPE_SIZE > 0 */
372