Linux管道和系统调用pipe()

父进程和子进程之间,或者两个兄弟进程之间,可以通过系统调用建立起一个单向的通信管道。但是这种管道只能由父进程开建立,对于子进程来说是静态的,与生俱来的。管道两端的进程各自都将该管道视作一个文件。一个进程写,另一个进程读。并且,通过管道传递的内容遵循“先入先出”(FIFO)的原则。每个管道都是单向的,需要双向通信时就要建立两个管道。

二、系统调用pipe()

管道机制的主体是系统调用pipe(),但是由pipe()所建立的管道的两端都在同一进程中,所以必须在fork的配合下,才能在父子进程之间或者两个子进程之间建立起进程间的通信管道。由于管道两端都是以(已打开)文件的形式出现在相关的进程中,在具体实现上也是作为匿名文件来实现的。所以pipe()的代码与文件系统密切相关。

asmlinkage int sys_pipe(unsigned long * fildes){
    int fd[2];
    int error;
    error = do_pipe(fd);
    if(!error){
        if(copy_to_user(fildes, fd, 2 * sizeof(int)))
            error = -EFAULT; 
    }
    return error;               
}

这里由do_pipe()建立起一个管道,通过作为调用参数的数组fd[]返回代表着管道两端的两个已经打开文件号,,再由copy_to_user()将数组fd[]复制到用户空间。显然,do_pipe是这个系统调用的主题。

三、管道两端是否可以共享同一个file数据结构

在文件系统中,进程对每个已经打开文件的操作都是通过一个file数据结构进行的,只有在  由同一进程按照相同模式打开同一文件  时才共享同一个数据结构。一个管道实际上就是一个无形(只存在于内存中)的文件,对这个文件的操作要通过两个已经打开的文件进行,分别代表该管道的两端。虽然最初创建时一个管道的两端都在同一进程中,但是在实际使用时却总是分别在两个不同的进程。,所以,管道的两端不能共享同一个file数据结构。而要为止各分配一个file数据结构。

四、管道为什么需要inode结构?

每个文件都是有一个inode数据结构代表的。虽然一个管道实际上是一个无形的文件。但是也得有一个inode数据结构。由于这个文件在创建管道之前并不存在,所以需要在创建管道时临时创建一个inode结构(调用get_pipe_inode()函数)。

五、关于pipe_new()函数

pipe_new()函数,先分配一个内存页面用做管道的缓冲区,再分配一个缓冲区用作pipe_inode_info数据结构。为什么要这么做?用来实现管道的文件是无形的,它并不出现在磁盘或者其他的文件系统存储介质上,而只存在于内存空间,其他进程也无法“打开”或者访问这个文件。所以,这个所谓文件实质上只是一个用作缓冲区的内存页面,只是把它纳入了文件系统的机制,借用了文件系统的各种数据结构和操作加以管理。

六、对于管道的操作

inode数据结构中有个重要的成分i_fop,是指向一个file_operations数据结构的指针。这个数据结构中给出了用于该文件的每种操作的函数指针。对于管道来说,这个数据结构是rdwr_pipe_fops:

struct file_operations rdwr_pipe_fops = {
    llseek: pipe_lseek,
    read:  pipe_read,
    write:  pipe_write,
    poll:  pipe_poll,
    ioctl:  pipe_ioctl,
    open:  pipe_rdwr_open,
    release:pipe_rdwr_release,
};

函数get_pipe_inode()中分配了inode结构以后,进行了一些初始化操作。但是,代码中并没有设置inode结构中的inode_operations结构指针i_op,所以该指针为0.可见,对于用来实现管道的inode并不允许对这里的inode进行常规操作,只有当inode代表着“有形”的文件时才使用。

对于管道是否必须有目录项的问题:在正常情况下,每个文件都至少有一个“目录项”,代表着这个文件的路径名;而每个目录项则只描述一个文件,在denty数据结构中有个指针指向相应的inode结构。因此,在file数据结构中有个指针f_dentry指向做打开文件的目录项dentry数据结构,这样,从file结构开始就可以一路通道文件inode结构。但是,对于管道,文件是无形的,本来并非得有个目录项不可。可是,在file数据结构中并没有直接指向相应inode结构的指针,一定要经过一个目录项转换一下才行。然而inode结构又是各种文件操作的枢纽,所以对于管道也得有一个目录项了。故调用d_alloc()函数分配一个目录项,然后通过d_add()使已经分配的inode结构,与这个函数挂上钩,并且让两个已经打开文件结构中的f_entry()指针都指向这个目录。另外,对于管道的目录项的操作只允许删除操作。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/13274.html