NOTE
Pipe数据结构
- Struct inode{
- …
- atomic_t i_count; //节点引用计数
- struct pipe_inode_info *i_pipe;
- …
- }
- struct pipe_inode_info {
- wait_queue_head_t wait; //等待队列
- char *base; //分配的共享页面地址
- unsigned int start; //起始位置的偏移量
- unsigned int readers; //读文件对象的个数filp, get_pipe_inode() 此项被置1,撤销了filp(filp->f_count=0 调用pipe_release),此项-1
- unsigned int writers; //写文件对象的个数filp,
- unsigned int waiting_readers; //阻塞的读文件对象个数
- unsigned int waiting_writers; //阻塞的写文件对象个数
- unsigned int r_counter; //fifo读打开的次数
- unsigned int w_counter; //fifo写打开的次数
- };
宏
- #define PIPE_SIZE PAGE_SIZE
- #define PIPE_SEM(inode) (&(inode).i_sem)
- #define PIPE_WAIT(inode) (&(inode).i_pipe->wait)
- #define PIPE_BASE(inode) ((inode).i_pipe->base)
- #define PIPE_START(inode) ((inode).i_pipe->start)
- #define PIPE_LEN(inode) ((inode).i_size)
- #define PIPE_READERS(inode) ((inode).i_pipe->readers)
- #define PIPE_WRITERS(inode) ((inode).i_pipe->writers)
- #define PIPE_WAITING_READERS(inode) ((inode).i_pipe->waiting_readers)
- #define PIPE_WAITING_WRITERS(inode) ((inode).i_pipe->waiting_writers)
- #define PIPE_RCOUNTER(inode) ((inode).i_pipe->r_counter)
- #define PIPE_WCOUNTER(inode) ((inode).i_pipe->w_counter)
- #define PIPE_EMPTY(inode) (PIPE_LEN(inode) == 0)
- #define PIPE_FULL(inode) (PIPE_LEN(inode) == PIPE_SIZE)
- #define PIPE_FREE(inode) (PIPE_SIZE - PIPE_LEN(inode))
- #define PIPE_END(inode) ((PIPE_START(inode) + PIPE_LEN(inode)) & (PIPE_SIZE-1))
- #define PIPE_MAX_RCHUNK(inode) (PIPE_SIZE - PIPE_START(inode))
- #define PIPE_MAX_WCHUNK(inode) (PIPE_SIZE - PIPE_END(inode))
二 .管道读取的情景分析:
1如果管道为空
管道无生产者(写端被关闭了)ret:0
非阻塞(O_NONBLOCK)的方式度管道(默认为阻塞),ret:0
阻塞,做如下判断
(1)进程自我阻塞直到被唤起
(2)管道非空,跳到2
(3)无写者,ret : 0
(4)到这了,说明进程的唤起和本管道没有太大的关系,继续到(1)进入睡眠直到被唤起
2管道非空
读管道,管道其实是个页面缓存,他的读法下面介绍
如果:管道的数据(size)不够读取(count)
在阻塞及有生产者的情况下,唤起生产者,跳到1. 。
否则ret:read
Ps:得出的一般结论,如果在阻塞的情况下读取管道的返回值ret小于预期要读取的字节数count,可判断为管道没有生产者了(写端被关闭)
三. 读取非空的管道
Count:为预期要在管道读的字节数
PIPE_LEN:管道中的字节数
PIPE_BASE:缓冲页面起始地址
PIPE_START:内容的偏移量
PIPE_END(inode) ((PIPE_START(inode) + PIPE_LEN(inode)) & (PIPE_SIZE-1)) 内容的结束位置
PIPE_MAX_RCHUNK(inode) (PIPE_SIZE - PIPE_START(inode)) 内容开始到页面低的容量
缓冲页面的各个参数如下图所示:
页面的使用时循环的
读取管道数据的代码如下:
- while (count > 0 && (size = PIPE_LEN(*inode))) {
- char *pipebuf = PIPE_BASE(*inode) + PIPE_START(*inode); //数据的起始位置
- ssize_t chars = PIPE_MAX_RCHUNK(*inode); //start到一面尾的长度
- if (chars > count)
- chars = count;
- if (chars > size)
- chars = size;
- //chars取 count,size, PIPE_MAX_RCHUNK的最小值
- if (copy_to_user(buf, pipebuf, chars)) //将pipebuf中的chars个字节拷贝到用户空间的buf
- goto out;
- read += chars; //已经读取了read个字节
- PIPE_START(*inode) += chars; //移动start推移:度过的数据就丢弃
- PIPE_START(*inode) &= (PIPE_SIZE - 1); // start%=pagesize
- PIPE_LEN(*inode) -= chars; //管道中的数据量减chars
- count -= chars; //与读取的数据量减chars
- buf += chars; //用户空间缓冲的填充指针
- }
情况1:PIPE_MAX_RCHUNK>PIPE_LEN>count
Chars=count
读取后的pipe
情况2:PIPE_MAX_RCHUNK> count> PIPE_LEN
Chars=pipe_len,读取后进程进入阻塞(非阻塞返回chars),并且PIPE_START=PIPE_END=0
情况3 :PIPE_LEN > PIPE_MAX_RCHUNK> count
Chars=count,和情况一是一个效果。
情况4: PIPE_LEN >count>PIPE_MAX_RCHUNK
chars= PIPE_MAX_RCHUNK
chars=count
接着便是情况1的读取方式了。
情况5:count>PIPE_LEN > PIPE_MAX_RCHUNK
1.chars= PIPE_MAX_RCHUNK
.chars=PIPE_SIZE ,接着便是情况2的读取方式了
阅读(2018) | 评论(0) | 转发(0) |