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