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 51static int pipe_close(struct file *filep); 52#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS 53int pipe_unlink(struct Vnode *priv); 54#endif 55 56/**************************************************************************** 57 * Private Data 58 ****************************************************************************/ 59 60static 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 66static 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 81static sem_t g_pipesem = {NULL}; 82static uint32_t g_pipeset = 0; 83static uint32_t g_pipecreated = 0; 84 85/**************************************************************************** 86 * Private Functions 87 ****************************************************************************/ 88 89/**************************************************************************** 90 * Name: pipe_allocate 91 ****************************************************************************/ 92 93static 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 115static 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 131static 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 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 211static 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 242int 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 337errout_with_wrfd: 338 close(fd[1]); 339 340errout_with_driver: 341 unregister_driver(devname); 342 (void)sem_wait(&g_pipesem); 343 g_pipecreated &= ~(1 << pipeno); 344 (void)sem_post(&g_pipesem); 345 346errout_with_dev: 347 if (dev) 348 { 349 pipecommon_freedev(dev); 350 } 351 352errout_with_pipe: 353 pipe_free(pipeno); 354 355errout: 356 set_errno(errcode); 357 return VFS_ERROR; 358} 359 360int pipe_init(void) 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 369LOS_MODULE_INIT(pipe_init, LOS_INIT_LEVEL_KMOD_EXTENDED); 370 371#endif /* CONFIG_DEV_PIPE_SIZE > 0 */ 372