Linux-0.11 文件系统pipe.c详解

news/2025/2/21 2:37:35/

Linux-0.11 文件系统pipe.c详解

模块简介

在Linux-0.11中提供了管道这种进程间通讯的方式。本程序包含了管道文件读写操作函数read_pipe()和write_pipe()。

函数详解

read_pipe

int read_pipe(struct m_inode * inode, char * buf, int count)

该函数是读管道的方法。

pipe

函数的最初定义了一些参数,其中chars为需要复制的字符数,size的作用有两个,在下面的代码中会根据代码介绍,read参数代表已经读取的字符数。

int chars, size, read = 0;

因为管道的大小最大只有4k,因此当count的值大于4K时,就涉及到多次读,因此通过一个大的循环,当count值大于0,便循环执行下面的操作。如果管道中的数据长度为0,那么就唤醒等待该管道inode的进程(通常是写pipe的进程)。如果目前没有写管道的进程,意味着当前pipe不可能读到数据,则将当前进程加入到等待该inode的队列中。

while (count>0) {while (!(size=PIPE_SIZE(*inode))) {wake_up(&inode->i_wait);if (inode->i_count != 2) /* are there any writers? */return read;sleep_on(&inode->i_wait);}

进入到这里,意味着管道有数据可读。令chars的值等于管道尾指针到缓冲区末端的字节数。 如果其大于count值,那么令其等于count。如果chars大于管道中含有数据的长度size, 则令chars等于size。接下来令剩下待读的字符数减去chars,令已经读取的字符数read加上chars。

chars = PAGE_SIZE-PIPE_TAIL(*inode);
if (chars > count)chars = count;
if (chars > size)chars = size;
count -= chars;
read += chars;

接下来将size指向原来尾指针的位置,将尾指针向前移动chars,如果超过4k,则返回头重新开始。最后调用put_fs_byte将管道中的数据复制到用户缓冲区中。

size = PIPE_TAIL(*inode);
PIPE_TAIL(*inode) += chars;
PIPE_TAIL(*inode) &= (PAGE_SIZE-1);
while (chars-->0)put_fs_byte(((char *)inode->i_size)[size++],buf++);

最后,本次读管道操作结束,唤醒等待该管道的进程。

wake_up(&inode->i_wait);
return read;

write_pipe

int write_pipe(struct m_inode * inode, char * buf, int count)

该函数是管道的写操作函数。

函数的开始定义了一些参数,其中chars是要写入管道的数量,size有多个作用,written是已经写入的字符数量。

int chars, size, written = 0;

因为管道的大小最大只有4k,因此当count的值大于4K时,就涉及到多次写,因此通过一个大的循环,当count值大于0,便循环执行下面的操作。如果当前管道已经满,那么便唤醒等待该pipe inode的进程(读进程)。如果当前的inode节点没有其他的读进程,则发送SIGPIPE信号到进程。否则的话,则将当前进程加入sleep队列,直到pipe inode可写。

while (count>0) {while (!(size=(PAGE_SIZE-1)-PIPE_SIZE(*inode))) {wake_up(&inode->i_wait);if (inode->i_count != 2) { /* no readers */current->signal |= (1<<(SIGPIPE-1));return written?written:-1;}sleep_on(&inode->i_wait);}

程序执行到这里,代表该管道当前有空间可写。首先获取管道头到缓冲区末端的字节数chars。如果chars大小大于count,则令chars等于count。接下来如果chars大于size值,则令chars等于size。接下来令count值减去chars值,令已写数据written加上chars值。

chars = PAGE_SIZE-PIPE_HEAD(*inode);
if (chars > count)chars = count;
if (chars > size)chars = size;
count -= chars;
written += chars;

最后将size指向头节点,将PIPE_HEAD向前推进chars个字符。最后调用get_fs_byte,从buf拷贝数据到pipe缓冲区中。

size = PIPE_HEAD(*inode);
PIPE_HEAD(*inode) += chars;
PIPE_HEAD(*inode) &= (PAGE_SIZE-1);
while (chars-->0)((char *)inode->i_size)[size++]=get_fs_byte(buf++);

最后唤醒等待该pipe的进程,并返回已写入的字节数。

    wake_up(&inode->i_wait);return written;

sys_pipe

int sys_pipe(unsigned long * fildes)

该函数是创建管道pipe函数的系统调用。

入参fildes是管道的文件描述符,(fildes+0)是读端,(fildes+1)是写端。

程序的开始,定义了一系列变量。其中,inode用于获取管道类型的inode。f数组用于从文件表中找到两个空位。fd数组是管道的读端和写端。 i和j用于遍历。

    struct m_inode * inode;struct file * f[2];int fd[2];int i,j;

接下来要做的就是从全局文件表file_table中找到两个空位。如果找不到两个空位,就返回-1。

    j=0;for(i=0;j<2 && i<NR_FILE;i++)if (!file_table[i].f_count)(f[j++]=i+file_table)->f_count++;if (j==1)f[0]->f_count=0;if (j<2)return -1;

接下来从进程的文件表中获取两个空位,用于填充文件描述符数组fd[2]。同样,如果没有两个空位,则返回-1。

    j=0;for(i=0;j<2 && i<NR_OPEN;i++)if (!current->filp[i]) {current->filp[ fd[j]=i ] = f[j];j++;}if (j==1)current->filp[fd[0]]=NULL;if (j<2) {f[0]->f_count=f[1]->f_count=0;return -1;}

接下来便是获取一个空的inode节点用作管道读写的inode。如果没有空的inode节点,则返回-1。

    if (!(inode=get_pipe_inode())) {current->filp[fd[0]] =current->filp[fd[1]] = NULL;f[0]->f_count = f[1]->f_count = 0;return -1;}

如果管道inode节点申请成功,则对两个文件结构进行初始化。并通过put_fs_long将文件描述符拷贝到入参fildes中。

    f[0]->f_inode = f[1]->f_inode = inode;f[0]->f_pos = f[1]->f_pos = 0;f[0]->f_mode = 1;		/* read */f[1]->f_mode = 2;		/* write */put_fs_long(fd[0],0+fildes);put_fs_long(fd[1],1+fildes);

Q & A


http://www.ppmy.cn/news/96420.html

相关文章

第4章 Container

第4章 Container reference 引用 Declaring references Reference is a new way to manipulate objects in C – char c; // a character – char* p &c; // a pointer to a character – char &r c; // a reference to a character 区分指针*: int* p &…

C#调用FreeSpire.PDF获取PDF文档中使用的字体

除了图片之外&#xff0c;电子文件中使用的字体都必须要在本机中安装才能正常查看文字&#xff08;word缺少字体的话会自动使用相似或默认字体&#xff09;&#xff0c;要想知道电子文件中使用的字体&#xff0c;可以将电子文件转换为PDF文件&#xff08;如果是打印成PDF的话&a…

C++环形缓冲区设计与实现:从原理到应用的全方位解析

C环形缓冲区设计与实现&#xff1a;从原理到应用的全方位解析 一、环形缓冲区基础理论解析&#xff08;Basic Theory of Circular Buffer&#xff09;1.1 环形缓冲区的定义与作用&#xff08;Definition and Function of Circular Buffer&#xff09;1.2 环形缓冲区的基本原理&…

Visual Studio2022编译器实用调试技巧

目录 1.什么是bug 2.调试是什么&#xff1f; 3.debug和release的介绍 4.windows环境调试介绍 4.1 调试环境的准备 4.2 学会快捷键 4.3 调试的时候查看程序当前信息 4.4 查看内存信息 5.如果写出好&#xff08;易于调试&#xff09;的代码 7.编程常见的错误 1.什么是b…

Day2:Windows网络编程-TCP

今天开始进入Windows网络编程的学习&#xff0c;在学习的时候总是陷入Windows复杂的参数&#xff0c;纠结于这些。从老师的讲解中&#xff0c;这些内容属于是定式&#xff0c;主要学习写的逻辑。给自己提个醒&#xff0c;要把精力放在正确的位置&#xff0c;不要无端耗费精力。…

指针数组和数组指针

//void test(int arr[]) //{ // int sz sizeof(arr) / sizeof(arr[0]); // printf("%d\n", sz);//计算的是 // //地址除元素的大小的值 32位 ֵ值为1 64位 值为2 //} //int main() //{ // int arr[10] { 0 }; // test(arr); // char ch w; // …

String类的学习笔记(下):字符串拼接以及StringBuilder和StringBuffer的学习

本文介绍了String类对字符串进行拼接的方法 和拼接字符串的效率分析 以及能对字符串内容进行修改的StringBuilder和StringBuffer类其常用方法和区别 , 最后介绍了两个字符串经典面试题 StringBuilder和StringBuffer的学习 一.String类概括二.StringBuilder和StringBuffer1.字符…

第一节 Python 顺序结构

1 . Python 介绍 1.1 Python是什么 Python是一种高级编程语言,具有简单易学、功能强大、可扩展性好等特点,是目前广泛应用于Web开发、数据分析、人工智能等领域的编程语言之一。 Python的历史可以追溯到1989年,当时在荷兰的Guido van Rossum开发了这种语言,Guido最初设计P…