Linux pipe 源代码分析

     管道pipe作为Unix中历史最悠久的IPC机制,存在各个版本号的Unix中,主要用于父子进程之间的通信(使用fork,从而子进程会获得父进程的打开文件表)。pipe()系统调用底层的实现就相当于一个特殊的文件系统,每次调用的时候创建一个inode关联着两个file。一个用于读,一个用于写。从而实现数据的单向流动。

用户层API:
 #include <unistd.h>

       int pipe(int pipefd[2]);

       #define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <unistd.h> int pipe2(int pipefd[2], int flags);

内核源代码路径例如以下:
// sys_pipe(.......)
SYSCALL_DEFINE1(pipe, int __user *, fildes)
{
return sys_pipe2(fildes, 0);
} SYSCALL_DEFINE2(pipe2, int __user *, fildes, int, flags)
{
struct file *files[2];
int fd[2];
int error;
// 核心是do_pipe
error = __do_pipe_flags(fd, files, flags);
if (!error) {
// 一切准备就绪后 把刚才和管道关联的2个fd复制到用户空间
if (unlikely(copy_to_user(fildes, fd, sizeof(fd)))) {
fput(files[0]);
fput(files[1]);
put_unused_fd(fd[0]);
put_unused_fd(fd[1]);
error = -EFAULT;
} else {
// 把fd和file的映射关系更新到该进程的文件描写叙述表中fdtable
fd_install(fd[0], files[0]);
fd_install(fd[1], files[1]);
}
}
return error;
} static int __do_pipe_flags(int *fd, struct file **files, int flags)
{
int error;
int fdw, fdr; if (flags & ~(O_CLOEXEC | O_NONBLOCK | O_DIRECT))
return -EINVAL;
// 为该管道创建俩struct file
error = create_pipe_files(files, flags);
if (error)
return error;
// 获得两个能用的文件描写叙述符
error = get_unused_fd_flags(flags);
if (error < 0)
goto err_read_pipe;
fdr = error; error = get_unused_fd_flags(flags);
if (error < 0)
goto err_fdr;
fdw = error; audit_fd_pair(fdr, fdw);
fd[0] = fdr;
fd[1] = fdw;
return 0; err_fdr:
put_unused_fd(fdr);
err_read_pipe:
fput(files[0]);
fput(files[1]);
return error;
} /*
* 为管道创建两个file实例
*/
int create_pipe_files(struct file **res, int flags)
{
int err;
// 为pipe创建一个inode并做一定的初始化
struct inode *inode = get_pipe_inode();
struct file *f;
struct path path;
static struct qstr name = { .name = "" }; // quick string ?? if (!inode)
return -ENFILE; err = -ENOMEM;
// 分配一个directory entry
path.dentry = d_alloc_pseudo(pipe_mnt->mnt_sb, &name);
if (!path.dentry)
goto err_inode;
path.mnt = mntget(pipe_mnt); // 引用计数加1 d_instantiate(path.dentry, inode); err = -ENFILE;
f = alloc_file(&path, FMODE_WRITE, &pipefifo_fops);
if (IS_ERR(f))
goto err_dentry; f->f_flags = O_WRONLY | (flags & (O_NONBLOCK | O_DIRECT));
f->private_data = inode->i_pipe;
// 所以你会明确 fd[0]是读 fd[1]是写
res[0] = alloc_file(&path, FMODE_READ, &pipefifo_fops);
if (IS_ERR(res[0]))
goto err_file; path_get(&path);
res[0]->private_data = inode->i_pipe;
res[0]->f_flags = O_RDONLY | (flags & O_NONBLOCK);
res[1] = f;
return 0; err_file:
put_filp(f);
err_dentry:
free_pipe_info(inode->i_pipe);
path_put(&path);
return err; err_inode:
free_pipe_info(inode->i_pipe);
iput(inode);
return err;
} static struct inode * get_pipe_inode(void)
{
struct inode *inode = new_inode_pseudo(pipe_mnt->mnt_sb);
struct pipe_inode_info *pipe; if (!inode)
goto fail_inode;
// 分配一个inode号
inode->i_ino = get_next_ino();
// 分配一个pipe的内核级对象
pipe = alloc_pipe_info();
if (!pipe)
goto fail_iput; inode->i_pipe = pipe;
pipe->files = 2;
pipe->readers = pipe->writers = 1;
inode->i_fop = &pipefifo_fops; /*
* Mark the inode dirty from the very beginning,
* that way it will never be moved to the dirty
* list because "mark_inode_dirty()" will think
* that it already _is_ on the dirty list.
*/
inode->i_state = I_DIRTY;
inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; return inode; fail_iput:
iput(inode); fail_inode:
return NULL;
} // 针对pipe的文件操作实例
const struct file_operations pipefifo_fops = {
.open = fifo_open,
.llseek = no_llseek,
.read = new_sync_read,
.read_iter = pipe_read,
.write = new_sync_write,
.write_iter = pipe_write,
.poll = pipe_poll,
.unlocked_ioctl = pipe_ioctl,
.release = pipe_release,
.fasync = pipe_fasync,
};
总体的逻辑图能够这样:
TODO:详细读写的实现细节new_sync_read/write()有待分析。
參考:
(1)Linux kernel 3.18 source code 
(2)Linux man page
(3)Linux内核源代码情景分析

Linux pipe 源代码分析的更多相关文章

  1. Linux内核源代码分析方法

    Linux内核源代码分析方法   一.内核源代码之我见 Linux内核代码的庞大令不少人"望而生畏",也正由于如此,使得人们对Linux的了解仅处于泛泛的层次.假设想透析Linux ...

  2. linux下源代码分析和阅读工具比较

    Windows下的源码阅读工具Souce Insight凭借着其易用性和多种编程语言的支持,无疑是这个领域的“带头大哥”.Linux/UNIX环境下呢?似乎仍然是处于百花齐放,各有千秋的春秋战国时代, ...

  3. Linux 内核源代码分析 chap 2 存储管理 (5)

    物理页面分配 linux 内核 2.4 中有 2 个版本号的物理页面分配函数 alloc_pages(). 一个在 mm/numa.c 中, 还有一个在 mm/page_alloc.c 中, 依据条件 ...

  4. linux 内核源代码分析 - 获取数组的大小

    #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 測试程序: #include<stdio.h> #include<stdlib. ...

  5. ARMv8 Linux内核源代码分析:__flush_dcache_all()

    1.1 /* *  __flush_dcache_all() *  Flush the wholeD-cache. * Corrupted registers: x0-x7, x9-x11 */ EN ...

  6. 【转载】linux环境下tcpdump源代码分析

    linux环境下tcpdump源代码分析 原文时间 2013-10-11 13:13:02  CSDN博客 原文链接  http://blog.csdn.net/han_dawei/article/d ...

  7. linux环境下tcpdump源代码分析

    Linux 环境下tcpdump 源代码分析 韩大卫@吉林师范大学 tcpdump.c 是tcpdump 工具的main.c, 本文旨对tcpdump的框架有简单了解,只展示linux平台使用的一部分 ...

  8. Linux内核源代码情景分析系列

    http://blog.sina.com.cn/s/blog_6b94d5680101vfqv.html Linux内核源代码情景分析---第五章 文件系统  5.1 概述 构成一个操作系统最重要的就 ...

  9. Hadoop源代码分析

    http://wenku.baidu.com/link?url=R-QoZXhc918qoO0BX6eXI9_uPU75whF62vFFUBIR-7c5XAYUVxDRX5Rs6QZR9hrBnUdM ...

随机推荐

  1. 客户端和服务器最多能发送和接收多少TCP连接数?

    1. 对于服务器,每一个tcp连接都要占一个文件描述符,一旦这个文件描述符使用完了,就会返回错误. 我们知道操作系统上端口号1024以下是系统保留的,从1024-65535是用户使用的.由于每个TCP ...

  2. spoj-TSUM Triple Sums

    题目描述 题解: 很吊的容斥+$FFT$,但是并不难. 首先,由于有重复,我们要容斥. 怎么办? 记录三个多项式, 只取一个:$w1$; 相同物体拿两个:$w2$; 相同物体拿三个:$w3$; 然后答 ...

  3. Openjudge-4115-佐助和鸣人

    这一题是一道广搜的题目,首先我们通过读入字符串读入每一行,然后顺带找到鸣人的位置. 然后我们初始化之后,就进行广搜,还是广搜的格式,但是要压入队列的条件我们可以稍微变一变,我们可以直接判断下一个要走的 ...

  4. 解决 【xshell 5 不能使用退格键和Delete建】的问题

    ###按照图片操作即可 1,打开[文件],选择[打开]选项 2.在会话中,打开[属性] 3.点击左边[终端]下的[键盘]选项,按照如下设置 即可.

  5. 深入Linux内核架构——锁与进程间通信

    Linux作为多任务系统,当一个进程生成的数据传输到另一个进程时,或数据由多个进程共享时,或进程必须彼此等待时,或需要协调资源的使用时,应用程序必须彼此通信. 一.控制机制 1.竞态条件 几个进程在访 ...

  6. (十七)python 3 函数递归

    递归函数 即自己调用自己,递归中可以函数自身调用自身,但是使用时类似于条件循环一样,要有递归的终止条件 优点:使用递归时,常常可以让代码更加简洁 缺点:递归会占用比较多的内存,当递归次数比较多时,性能 ...

  7. Vijos1144 皇宫看守 (0/1/2三种状态的普通树形Dp)

    题意: 给出一个树以及一些覆盖每个点的花费,求每个点都能被自己被覆盖,或者相邻的点被覆盖的最小价值. 细节: 其实我乍一眼看过去还以为是 战略游戏 的复制版 可爱的战略游戏在这里QAQ(请原谅这波广告 ...

  8. python--如何在线上环境优雅的修改配置文件?

    1.如何在线上环境优雅的修改配置文件? 原配置文件 #原配置文件 global log 127.0.0.1 local2 daemon maxconn 256 log 127.0.0.1 local2 ...

  9. 七牛云 GO 语言周报【七月第 2 期】

    全世界有多少 Gopher? 上周的周报中,我们介绍了 Go 语言的排名已经进入到前十.那么世界上到底有多少 Gopher 呢? 作者列出了以下计算公式: Gopher 数量 = 全世界的开发者数量 ...

  10. C#中将数字金额转成英文大写金额的函数

    <span style="white-space:pre"> </span>/// <summary> /// 数字转金额大写 /// 调用示例 ...