int pipecommon_unlink(FAR struct inode *inode) { FAR struct pipe_dev_s *dev; DEBUGASSERT(inode && inode->i_private); dev = (FAR struct pipe_dev_s *)inode->i_private; /* Mark the pipe unlinked */ PIPE_UNLINK(dev->d_flags); /* Are the any open references to the driver? */ if (dev->d_refs == 0) { /* No.. free the buffer (if there is one) */ if (dev->d_buffer) { kmm_free(dev->d_buffer); } /* And free the device structure. */ pipecommon_freedev(dev); } return OK; }
int mkfifo(FAR const char *pathname, mode_t mode) { struct pipe_dev_s *dev; int ret; /* Allocate and initialize a new device structure instance */ dev = pipecommon_allocdev(); if (!dev) { return -ENOMEM; } ret = register_driver(pathname, &fifo_fops, mode, (void*)dev); if (ret != 0) { pipecommon_freedev(dev); } return ret; }
int pipecommon_close(FAR struct file *filep) { struct inode *inode = filep->f_inode; struct pipe_dev_s *dev = inode->i_private; int sval; DEBUGASSERT(dev && dev->d_refs > 0); /* Make sure that we have exclusive access to the device structure. * NOTE: close() is supposed to return EINTR if interrupted, however * I've never seen anyone check that. */ pipecommon_semtake(&dev->d_bfsem); /* Decrement the number of references on the pipe. Check if there are * still outstanding references to the pipe. */ /* Check if the decremented reference count would go to zero */ if (--dev->d_refs > 0) { /* No more references.. If opened for writing, decrement the count of * writers on the pipe instance. */ if ((filep->f_oflags & O_WROK) != 0) { /* If there are no longer any writers on the pipe, then notify all of the * waiting readers that they must return end-of-file. */ if (--dev->d_nwriters <= 0) { while (sem_getvalue(&dev->d_rdsem, &sval) == 0 && sval < 0) { sem_post(&dev->d_rdsem); } /* Inform poll readers that other end closed. */ pipecommon_pollnotify(dev, POLLHUP); } } /* If opened for reading, decrement the count of readers on the pipe * instance. */ if ((filep->f_oflags & O_RDOK) != 0) { if (--dev->d_nreaders <= 0) { if (PIPE_IS_POLICY_0(dev->d_flags)) { /* Inform poll writers that other end closed. */ pipecommon_pollnotify(dev, POLLERR); } } } } /* What is the buffer management policy? Do we free the buffe when the * last client closes the pipe policy 0, or when the buffer becomes empty. * In the latter case, the buffer data will remain valid and can be * obtained when the pipe is re-opened. */ else if (PIPE_IS_POLICY_0(dev->d_flags) || dev->d_wrndx == dev->d_rdndx) { /* Policy 0 or the buffer is empty ... deallocate the buffer now. */ kmm_free(dev->d_buffer); dev->d_buffer = NULL; /* And reset all counts and indices */ dev->d_wrndx = 0; dev->d_rdndx = 0; dev->d_refs = 0; dev->d_nwriters = 0; dev->d_nreaders = 0; #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS /* If, in addition, we have been unlinked, then also need to free the * device structure as well to prevent a memory leak. */ if (PIPE_IS_UNLINKED(dev->d_flags)) { pipecommon_freedev(dev); return OK; } #endif } sem_post(&dev->d_bfsem); return OK; }
int pipe(int fd[2]) { FAR struct pipe_dev_s *dev = NULL; char devname[16]; int pipeno; int err; int ret; /* Get exclusive access to the pipe allocation data */ ret = sem_wait(&g_pipesem); if (ret < 0) { /* sem_wait() will have already set errno */ return ERROR; } /* Allocate a minor number for the pipe device */ pipeno = pipe_allocate(); if (pipeno < 0) { (void)sem_post(&g_pipesem); err = -pipeno; goto errout; } /* Create a pathname to the pipe device */ sprintf(devname, "/dev/pipe%d", pipeno); /* Check if the pipe device has already been created */ if ((g_pipecreated & (1 << pipeno)) == 0) { /* No.. Allocate and initialize a new device structure instance */ dev = pipecommon_allocdev(); if (!dev) { (void)sem_post(&g_pipesem); err = ENOMEM; goto errout_with_pipe; } dev->d_pipeno = pipeno; /* Register the pipe device */ ret = register_driver(devname, &pipe_fops, 0666, (FAR void *)dev); if (ret != 0) { (void)sem_post(&g_pipesem); err = -ret; goto errout_with_dev; } /* Remember that we created this device */ g_pipecreated |= (1 << pipeno); } (void)sem_post(&g_pipesem); /* Get a write file descriptor */ fd[1] = open(devname, O_WRONLY); if (fd[1] < 0) { err = -fd[1]; goto errout_with_driver; } /* Get a read file descriptor */ fd[0] = open(devname, O_RDONLY); if (fd[0] < 0) { err = -fd[0]; goto errout_with_wrfd; } return OK; errout_with_wrfd: close(fd[1]); errout_with_driver: unregister_driver(devname); errout_with_dev: if (dev) { pipecommon_freedev(dev); } errout_with_pipe: pipe_free(pipeno); errout: set_errno(err); return ERROR; }