linux pipe 缓冲大小,linux下,pipe的容量的讨论与查看

本文探讨了Linux内核中的pipe缓冲区大小,通常为64KB,由16个4KB的缓冲条目组成。通过`ulimit -a`可以查看pipe的大小,实际为16*4096Bytes。pipe的内部组织利用了文件系统的file结构和VFS的索引节点,通过两个file结构和一个VFS索引节点实现。同时,文章还介绍了如何查看具体系统上的pipe大小,并展示了pipe_inode_info结构和pipe_buffer结构的关键元素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、pipe的容量

98b0da182fe9935e30ecbbe1fcb6ef41.png

2.6标准版本的linux内核,pipe缓冲区是64KB,尽管命令ulimit -a看到管道大小8块,缓冲区的大小不是4 k,因为内核动态分配最大16“缓冲条目”,乘64 k。这些限制是硬编码的

2、如何查看自己pc上的pipe多大

1)通过ulimit -a查看到 pipe size 一次原子写入为:512Bytes*8=4096Bytes

3da023cc363facfef498f42a5dc77ea0.png

查看缓冲条目个数:cat /usr/src/kernels/3.10.0-327.el7.x86_64/include/linux/pipe_fs_i.h文件

fbe64afb67ef8db27b20c94c2d48096c.png

所以我的pc下得pipe缓冲大小为:16*4096=65536Bytes

也就验证了man 7 pipe下的pipe capacity

d508b5b6a24ed2c88c06d0e7542f03a0.png

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_BUFFERS16

#define PIPE_BUF_FLAG_LRU0x01/* page is on the LRU */

#define PIPE_BUF_FLAG_ATOMIC0x02/* was atomically mapped */

#define PIPE_BUF_FLAG_GIFT0x04/* page is a gift */

#define PIPE_BUF_FLAG_PACKET0x08/* 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_SIZEPAGE_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通知

};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值