1、pipe的容量
2.6标准版本的linux内核,pipe缓冲区是64KB,尽管命令ulimit -a看到管道大小8块,缓冲区的大小不是4 k,因为内核动态分配最大16“缓冲条目”,乘64 k。这些限制是硬编码的
2、如何查看自己pc上的pipe多大
1)通过ulimit -a查看到 pipe size 一次原子写入为:512Bytes*8=4096Bytes
查看缓冲条目个数:cat /usr/src/kernels/3.10.0-327.el7.x86_64/include/linux/pipe_fs_i.h文件
所以我的pc下得pipe缓冲大小为:16*4096=65536Bytes
也就验证了man 7 pipe下的pipe capacity
3、pipe的内部组织方式
在 Linux 中,管道的实现并没有使用专门的数据结构,而是借助了文件系统的file结构和VFS的索引节点inode。通过将两个 file 结构指向同一个临时的 VFS 索引节点,而这个 VFS 索引节点又指向一个物理页面而实现的。
有两个 file 数据结构,但它们定义文件操作例程地址是不同的,其中一个是向管道中写入数据的例程地址,而另一个是从管道中读出数据的例程地址。这样,用户程序的系统调用仍然是通常的文件操作,而内核却利用这种抽象机制实现了管道这一特殊操作。
cat /usr/src/kernels/3.10.0-327.el7.x86_64/include/linux/pipe_fs_i.h文件
#ifndef _LINUX_PIPE_FS_I_H #define _LINUX_PIPE_FS_I_H #define PIPE_DEF_BUFFERS 16 #define PIPE_BUF_FLAG_LRU 0x01 /* page is on the LRU */ #define PIPE_BUF_FLAG_ATOMIC 0x02 /* was atomically mapped */ #define PIPE_BUF_FLAG_GIFT 0x04 /* page is a gift */ #define PIPE_BUF_FLAG_PACKET 0x08 /* read() as a packet */ /** * struct pipe_buffer - a linux kernel pipe buffer * @page: the page containing the data for the pipe buffer * @offset: offset of data inside the @page * @len: length of data inside the @page * @ops: operations associated with this buffer. See @pipe_buf_operations. * @flags: pipe buffer flags. See above. * @private: private data owned by the ops. **/ struct pipe_buffer { struct page *page; unsigned int offset, len; const struct pipe_buf_operations *ops; unsigned int flags; unsigned long private; }; /** * struct pipe_inode_info - a linux kernel pipe * @mutex: mutex protecting the whole thing * @wait: reader/writer wait point in case of empty/full pipe * @nrbufs: the number of non-empty pipe buffers in this pipe * @buffers: total number of buffers (should be a power of 2) * @curbuf: the current pipe buffer entry * @tmp_page: cached released page * @readers: number of current readers of this pipe * @writers: number of current writers of this pipe * @files: number of struct file refering this pipe (protected by ->i_lock) * @waiting_writers: number of writers blocked waiting for room * @r_counter: reader counter * @w_counter: writer counter * @fasync_readers: reader side fasync * @fasync_writers: writer side fasync * @bufs: the circular array of pipe buffers **/ struct pipe_inode_info { struct mutex mutex; wait_queue_head_t wait; unsigned int nrbufs, curbuf, buffers; unsigned int readers; unsigned int writers; unsigned int files; unsigned int waiting_writers; unsigned int r_counter; unsigned int w_counter; struct page *tmp_page; struct fasync_struct *fasync_readers; struct fasync_struct *fasync_writers; struct pipe_buffer *bufs; }; /* * Note on the nesting of these functions: * * ->confirm() * ->steal() * ... * ->map() * ... * ->unmap() * * That is, ->map() must be called on a confirmed buffer, * same goes for ->steal(). See below for the meaning of each * operation. Also see kerneldoc in fs/pipe.c for the pipe * and generic variants of these hooks. */ struct pipe_buf_operations { /* * This is set to 1, if the generic pipe read/write may coalesce * data into an existing buffer. If this is set to 0, a new pipe * page segment is always used for new data. */ int can_merge; /* * ->map() returns a virtual address mapping of the pipe buffer. * The last integer flag reflects whether this should be an atomic * mapping or not. The atomic map is faster, however you can‘t take * page faults before calling ->unmap() again. So if you need to eg * access user data through copy_to/from_user(), then you must get * a non-atomic map. ->map() uses the kmap_atomic slot for * atomic maps, you have to be careful if mapping another page as * source or destination for a copy. */ void * (*map)(struct pipe_inode_info *, struct pipe_buffer *, int); /* * Undoes ->map(), finishes the virtual mapping of the pipe buffer. */ void (*unmap)(struct pipe_inode_info *, struct pipe_buffer *, void *); /* * ->confirm() verifies that the data in the pipe buffer is there * and that the contents are good. If the pages in the pipe belong * to a file system, we may need to wait for IO completion in this * hook. Returns 0 for good, or a negative error value in case of * error. */ int (*confirm)(struct pipe_inode_info *, struct pipe_buffer *); /* * When the contents of this pipe buffer has been completely * consumed by a reader, ->release() is called. */ void (*release)(struct pipe_inode_info *, struct pipe_buffer *); /* * Attempt to take ownership of the pipe buffer and its contents. * ->steal() returns 0 for success, in which case the contents * of the pipe (the buf->page) is locked and now completely owned * by the caller. The page may then be transferred to a different * mapping, the most often used case is insertion into different * file address space cache. */ int (*steal)(struct pipe_inode_info *, struct pipe_buffer *); /* * Get a reference to the pipe buffer. */ void (*get)(struct pipe_inode_info *, struct pipe_buffer *); }; /* Differs from PIPE_BUF in that PIPE_SIZE is the length of the actual memory allocation, whereas PIPE_BUF makes atomicity guarantees. */ #define PIPE_SIZE PAGE_SIZE /* Pipe lock and unlock operations */ void pipe_lock(struct pipe_inode_info *); void pipe_unlock(struct pipe_inode_info *); void pipe_double_lock(struct pipe_inode_info *, struct pipe_inode_info *); extern unsigned int pipe_max_size, pipe_min_size; int pipe_proc_fn(struct ctl_table *, int, void __user *, size_t *, loff_t *); /* Drop the inode semaphore and wait for a pipe event, atomically */ void pipe_wait(struct pipe_inode_info *pipe); struct pipe_inode_info *alloc_pipe_info(void); void free_pipe_info(struct pipe_inode_info *); /* Generic pipe buffer ops functions */ void *generic_pipe_buf_map(struct pipe_inode_info *, struct pipe_buffer *, int); void generic_pipe_buf_unmap(struct pipe_inode_info *, struct pipe_buffer *, void *); void generic_pipe_buf_get(struct pipe_inode_info *, struct pipe_buffer *); int generic_pipe_buf_confirm(struct pipe_inode_info *, struct pipe_buffer *); int generic_pipe_buf_steal(struct pipe_inode_info *, struct pipe_buffer *); void generic_pipe_buf_release(struct pipe_inode_info *, struct pipe_buffer *); /* for F_SETPIPE_SZ and F_GETPIPE_SZ */ long pipe_fcntl(struct file *, unsigned int, unsigned long arg); struct pipe_inode_info *get_pipe_info(struct file *file); int create_pipe_files(struct file **, int); #endif
将上面的文件进行提取重要的结构
//inode结点信息结构 struct inode { ... struct pipe_inode_info *i_pipe; ... }; //管道缓冲区个数 #define PIPE_BUFFERS (16) //管道缓存区对象结构 struct pipe_buffer { struct page *page; //管道缓冲区页框的描述符地址 unsigned int offset, len; //页框内有效数据的当前位置,和有效数据的长度 struct pipe_buf_operations *ops; //管道缓存区方法表的地址 }; //管道信息结构 struct pipe_inode_info { wait_queue_head_t wait; //管道等待队列 unsigned int nrbufs, curbuf; //包含待读数据的缓冲区数和包含待读数据的第一个缓冲区的索引 struct pipe_buffer bufs[PIPE_BUFFERS]; //管道缓冲区描述符数组 struct page *tmp_page; //高速缓存区页框指针 unsigned int start; //当前管道缓存区读的位置 unsigned int readers; //读进程的标志,或编号 unsigned int writers; //写进程的标志,或编号 unsigned int waiting_writers; //在等待队列中睡眠的写进程的个数 unsigned int r_counter; //与readers类似,但当等待写入FIFO的进程是使用 unsigned int w_counter; //与writers类似,但当等待写入FIFO的进程时使用 struct fasync_struct *fasync_readers; //用于通过信号进行的异步I/O通知 struct fasync_struct *fasync_writers; //用于通过信号的异步I/O通知 };
本文出自 “momo就是辣么萌” 博客,请务必保留此出处http://momo462.blog.51cto.com/10138434/1825852
原文地址:http://momo462.blog.51cto.com/10138434/1825852