Linux Pipe Source Code Analysis
The pipe pipe, as the oldest IPC mechanism in UNIX, exists in Unix of each version number, primarily for communication between parent and child processes (using fork, so that the child process gets the open file table of the parent process). Pipe () system calls the underlying implementation is equivalent to a special file system, each time a call to create an inode associated with two file. One for reading and one for writing. Thus, one-way flow of data is realized.
User Layer API:
#include <unistd.h> int pipe (int pipefd[2]); #define _GNU_SOURCE/ * See Feature_test_macros (7) */ #include <unistd.h> int pipe2 (int pipefd[2], int flags);
the kernel source code path is as follows:
Sys_pipe (...) SYSCALL_DEFINE1 (pipe, int __user *, fildes) {return sys_pipe2 (fildes, 0);} Syscall_define2 (pipe2, int __user *, fildes, int, flags) {struct file *files[2]; int fd[2]; int error; The core is do_pipe error = __do_pipe_flags (fd, files, flags); if (!error) {//Everything is ready, copy the 2 fd that was just associated with the pipeline to the user space if (unlikely (Copy_to_user (Fildes, FD, sizeof))) { Fput (Files[0]); Fput (Files[1]); PUT_UNUSED_FD (Fd[0]); PUT_UNUSED_FD (fd[1]); Error =-efault; } else {//To update the mapping relationship of FD and file to the file descriptive narrative table of the process fdtable Fd_install (fd[0], files[0]); Fd_install (Fd[1], files[1]); }} return error;} static int __do_pipe_flags (int *fd, struct file **files, int flags) {int error; int FDW, FDR; if (Flags & ~ (O_cloexec | O_nonblock | O_direct)) Return-einval; Create two struct file error = Create_pipe_files for this pipeline (files, flags); if (error) return error; Get two available file descriptive descriptors error = Get_unused_fd_flags (flags); if (Error < 0) goto Err_read_pipe; FDR = error; Error = Get_unused_fd_flags (flags); if (Error < 0) goto ERR_FDR; FDW = error; Audit_fd_pair (FDR, FDW); Fd[0] = FDR; FD[1] = FDW; Return 0;ERR_FDR:PUT_UNUSED_FD (FDR); Err_read_pipe:fput (Files[0]); Fput (Files[1]); return error;} /** Create two file instances for pipelines */int create_pipe_files (struct file **res, int flags) {int err; Create an inode for the pipe and do some initialization of the struct inode *inode = Get_pipe_inode (); struct file *f; struct path path; static struct Qstr name = {. Name = ""}; Quick string?? if (!inode) return-enfile; err =-enomem; Assign a directory entry Path.dentry = D_alloc_pseudo (PIPE_MNT->MNT_SB, &name); if (!path.dentry) goto Err_inode; Path.mnt = Mntget (PIPE_MNT); Reference count plus 1 d_instantiate (path.dentrY, Inode); err =-enfile; f = Alloc_file (&path, Fmode_write, &pipefifo_fops); if (Is_err (f)) Goto err_dentry; F->f_flags = O_wronly | (Flags & (O_nonblock | O_direct)); F->private_data = inode->i_pipe; So you will be clear fd[0] is read Fd[1] is written res[0] = Alloc_file (&path, Fmode_read, &pipefifo_fops); if (Is_err (res[0])) goto Err_file; Path_get (&path); Res[0]->private_data = inode->i_pipe; Res[0]->f_flags = O_rdonly | (Flags & O_nonblock); Res[1] = f; Return 0;err_file:put_filp (f); Err_dentry:free_pipe_info (inode->i_pipe); Path_put (&path); Return Err;err_inode:free_pipe_info (Inode->i_pipe); Iput (Inode); return err;} static struct inode * Get_pipe_inode (void) {struct Inode *inode = New_inode_pseudo (PIPE_MNT->MNT_SB); struct Pipe_inode_info *pipe; if (!inode) goto Fail_inode; Assign an inode number Inode->i_ino = Get_next_ino (); Assign a pipe kernel-level object pipe = Alloc_pipe_info (); if (!pipe) goto fail_iput; Inode->i_pipe = pipe; Pipe->files = 2; Pipe->readers = Pipe->writers = 1; INODE->I_FOP = &pipefifo_fops; /* Mark the inode dirty from the very beginning, * That's the It'll never be moved to the dirty * list Becau Se "mark_inode_dirty ()" would think * that it already _is_ on the dirty list. */inode->i_state = I_dirty; Inode->i_mode = S_ififo | S_IRUSR | S_IWUSR; Inode->i_uid = Current_fsuid (); Inode->i_gid = Current_fsgid (); Inode->i_atime = Inode->i_mtime = Inode->i_ctime = Current_time; Return Inode;fail_iput:iput (inode); Fail_inode:return NULL;} File Operation example for pipe const struct File_operations pipefifo_fops = {. open = Fifo_open,. Llseek = no_l Lseek,. Read = New_sync_read,. Read_iter = Pipe_read,. Write = New_sync_write,. Write_iter = Pipe_write,. Poll = Pipe_poll,. Unlocked_ioctl = Pipe_ioctl,. Release = Pip E_release,. Fasync = Pipe_fasync,};
The overall logic diagram can do this:
TODO: detailed read and write implementation details new_sync_read/write () need to be analyzed.
References:(1) Linux kernel 3.18 source code?(2) Linux man page(3) Linux kernel source code scenario analysis
Linux Pipe Source Code Analysis