一、我们先来介绍一下init_pipe_fs。
static DECLARE_FSTYPE(pipe_fs_type, "pipefs", pipefs_read_super,
FS_NOMOUNT|FS_SINGLE);
static int __init init_pipe_fs(void)
{
int err = register_filesystem(&pipe_fs_type);
if (!err) {
pipe_mnt = kern_mount(&pipe_fs_type);
err = PTR_ERR(pipe_mnt);
if (IS_ERR(pipe_mnt))
unregister_filesystem(&pipe_fs_type);
else
err = 0;
}
return err;
}
struct vfsmount *kern_mount(struct file_system_type *type)
{
kdev_t dev = get_unnamed_dev();
struct super_block *sb;
struct vfsmount *mnt;
if (!dev)
return ERR_PTR(-EMFILE);
sb = read_super(dev, NULL, type, 0, NULL, 0);
if (!sb) {
put_unnamed_dev(dev);
return ERR_PTR(-EINVAL);
}
mnt = add_vfsmnt(NULL, sb->s_root, NULL);
if (!mnt) {
kill_super(sb, 0);
return ERR_PTR(-ENOMEM);
}
type->kern_mnt = mnt;
return mnt;
}
static struct super_block * read_super(kdev_t dev, struct block_device *bdev,
struct file_system_type *type, int flags,
void *data, int silent)
{
struct super_block * s;
s = get_empty_super();
if (!s)
goto out;
s->s_dev = dev;
s->s_bdev = bdev;
s->s_flags = flags;
s->s_dirt = 0;
sema_init(&s->s_vfs_rename_sem,1);
sema_init(&s->s_nfsd_free_path_sem,1);
s->s_type = type;
sema_init(&s->s_dquot.dqio_sem, 1);
sema_init(&s->s_dquot.dqoff_sem, 1);
s->s_dquot.flags = 0;
lock_super(s);
if (!type->read_super(s, data, silent))//指向pipefs_read_super
goto out_fail;
unlock_super(s);
/* tell bdcache that we are going to keep this one */
if (bdev)
atomic_inc(&bdev->bd_count);
out:
return s;
out_fail:
s->s_dev = 0;
s->s_bdev = 0;
s->s_type = NULL;
unlock_super(s);
return NULL;
}
type->read_super指向了pipefs_read_super,代码如下:
static struct super_block * pipefs_read_super(struct super_block *sb, void *data, int silent)
{
struct inode *root = new_inode(sb);//分配根节点的inode结构
if (!root)
return NULL;
root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
root->i_uid = root->i_gid = 0;
root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
sb->s_blocksize = 1024;
sb->s_blocksize_bits = 10;
sb->s_magic = PIPEFS_MAGIC;
sb->s_op = &pipefs_ops;
sb->s_root = d_alloc(NULL, &(const struct qstr) { "pipe:", 5, 0 });//分配根节点的dentry结构
if (!sb->s_root) {
iput(root);
return NULL;
}
sb->s_root->d_sb = sb;
sb->s_root->d_parent = sb->s_root;
d_instantiate(sb->s_root, root);//根节点的dentry和根节点的inode结构相连
return sb;
}
二、我们来看应用管道通信的相关代码,假设系统中只有这两个进程:
#include <stdio.h>
#include <unistd.h>
int main()
{
int n,fd[2];
pid_t pid;
int i,j;
char str1[]="ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE
ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE
ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE
ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE
ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE
ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE
ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE
ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE
ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE
ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE
ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE
ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE";
char str2[512];
if(pipe(fd)<0)//fd[0]是读端,fd[1]是写端
{
printf("pipe error\n");
return -1;
}
if((pid = fork())<0)//父子进程都有了同样file结构
{
printf("fork error\n");
return -1;
}else if(pid > 0)
{
close(fd[0]);//父进程做为写端,关闭读端
write(fd[1],str1,strlen(str1));
}
else
{
close(fd[1]);//子进程做为读端,关闭写端
read(fd[0],str2,strlen(str2));
}
}
pipe的系统调用是sys_pipe(),代码如下:
asmlinkage int sys_pipe(unsigned long * fildes)
{
int fd[2];
int error;
error = do_pipe(fd);//fd[]返回代表着管道两端的两个已打开文件号
if (!error) {
if (copy_to_user(fildes, fd, 2*sizeof(int)))//将数组fd[]复制到用户空间
error = -EFAULT;
}
return error;
}
int do_pipe(int *fd)
{
struct qstr this;
char name[32];
struct dentry *dentry;
struct inode * inode;
struct file *f1, *f2;
int error;
int i,j;
error = -ENFILE;
f1 = get_empty_filp();//获取读端空的file结构
if (!f1)
goto no_files;
f2 = get_empty_filp();//获取写端空的file结构
if (!f2)
goto close_f1;
inode = get_pipe_inode();//获取读端和写端共同使用的管道节点的inode结构
if (!inode)
goto close_f12;
error = get_unused_fd();//获得读端文件号
if (error < 0)
goto close_f12_inode;
i = error;
error = get_unused_fd();//获得写端文件号
if (error < 0)
goto close_f12_inode_i;
j = error;
error = -ENOMEM;
sprintf(name, "[%lu]", inode->i_ino);
this.name = name;
this.len = strlen(name);
this.hash = inode->i_ino; /* will go */
dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &this);//分配管道节点的dentry结构
if (!dentry)
goto close_f12_inode_i_j;
dentry->d_op = &pipefs_dentry_operations;
d_add(dentry, inode);//互相关联
f1->f_vfsmnt = f2->f_vfsmnt = mntget(mntget(pipe_mnt));
f1->f_dentry = f2->f_dentry = dget(dentry);//f_dentry指向所打开文件的目录项dentry数据结构
/* read file */
f1->f_pos = f2->f_pos = 0;
f1->f_flags = O_RDONLY;
f1->f_op = &read_pipe_fops;//读端的f_op
f1->f_mode = 1;
f1->f_version = 0;
/* write file */
f2->f_flags = O_WRONLY;
f2->f_op = &write_pipe_fops;//写端的f_op
f2->f_mode = 2;
f2->f_version = 0;
fd_install(i, f1);//f1安装到current->files[i]上
fd_install(j, f2);//f2安装到current->files[j]上
fd[0] = i;
fd[1] = j;
return 0;
close_f12_inode_i_j:
put_unused_fd(j);
close_f12_inode_i:
put_unused_fd(i);
close_f12_inode:
free_page((unsigned long) PIPE_BASE(*inode));
kfree(inode->i_pipe);
inode->i_pipe = NULL;
iput(inode);
close_f12:
put_filp(f2);
close_f1:
put_filp(f1);
no_files:
return error;
}
get_pipe_inode,获取读端和写端共同使用的管道节点的inode结构,代码如下:
static struct inode * get_pipe_inode(void)
{
struct inode *inode = get_empty_inode();
if (!inode)
goto fail_inode;
if(!pipe_new(inode))//分配所需要的缓冲区
goto fail_iput;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
inode->i_fop = &rdwr_pipe_fops;//这里以后会用到
inode->i_sb = pipe_mnt->mnt_sb;
/*
* 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;
inode->i_blksize = PAGE_SIZE;
return inode;
fail_iput:
iput(inode);
fail_inode:
return NULL;
}
pipe_new,分配所需要的缓冲区,代码如下:
struct inode* pipe_new(struct inode* inode)
{
unsigned long page;
page = __get_free_page(GFP_USER);
if (!page)
return NULL;
inode->i_pipe = kmalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);//i_pipe是指向一个pipe_inode_info数据结构的指针
if (!inode->i_pipe)
goto fail_page;
init_waitqueue_head(PIPE_WAIT(*inode));
PIPE_BASE(*inode) = (char*) page;//(inode).i_pipe->base指向了页面的起始地址
PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
PIPE_WAITING_READERS(*inode) = PIPE_WAITING_WRITERS(*inode) = 0;
PIPE_RCOUNTER(*inode) = PIPE_WCOUNTER(*inode) = 1;
return inode;
fail_page:
free_page(page);
return NULL;
}
pipe_inode_info结构如下:
struct pipe_inode_info {
wait_queue_head_t wait;
char *base;
unsigned int start;
unsigned int readers;
unsigned int writers;
unsigned int waiting_readers;
unsigned int waiting_writers;
unsigned int r_counter;
unsigned int w_counter;
};
pipe_new里面宏定义如下:
#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))
sys_pipe继续执行,对于管道的两端来说,管道是单向的,所以其f1一端设置成"只读",而另一端则设置成"只写"。同时,两端的文件操作也分别设置成read_pipe_fops和write_pipe_fops。
struct file_operations read_pipe_fops = {
llseek: pipe_lseek,
read: pipe_read,
write: bad_pipe_w,
poll: pipe_poll,
ioctl: pipe_ioctl,
open: pipe_read_open,
release: pipe_read_release,
};
struct file_operations write_pipe_fops = {
llseek: pipe_lseek,
read: bad_pipe_r,
write: pipe_write,
poll: pipe_poll,
ioctl: pipe_ioctl,
open: pipe_write_open,
release: pipe_write_release,
};
读者可能会问,前面管道节点的inode数据结构将指针i_fop设置成指向rdwr_pipe_fops,那显然是双向的。这里是不是有矛盾吗?其实不然,对于代表着管道两端的两个已打开文件来说,一个只能写而另一个只能读,这是事情的一个方面。可是另一方面,这两个逻辑上的已打开文件都通向同一个inode、同一个物理上存在的"文件",即用做管道的缓冲区;显然这个缓冲区应该既支持写又支持读,这样才能使数据流通。
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,
};
fork,父子进程都有相同的file结构,因为copy_file中有如下代码:
new_fds = newf->fd;
for (i = open_files; i != 0; i--) {
struct file *f = *old_fds++;
if (f)
get_file(f);
*new_fds++ = f;
}
tsk->files = newf;
我们假设父进程先执行,并且关闭了读端,执行write(fd[1],str1,strlen(str1)),映射到内核,sys_write,代码如下:
asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
{
ssize_t ret;
struct file * file;
ret = -EBADF;
file = fget(fd);
if (file) {
if (file->f_mode & FMODE_WRITE) {
struct inode *inode = file->f_dentry->d_inode;
ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
file->f_pos, count);
if (!ret) {
ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
ret = -EINVAL;
if (file->f_op && (write = file->f_op->write) != NULL)
ret = write(file, buf, count, &file->f_pos);//pipe_write
}
}
if (ret > 0)
inode_dir_notify(file->f_dentry->d_parent->d_inode,
DN_MODIFY);
fput(file);
}
return ret;
}
write(file, buf, count, &file->f_pos)调用pipe_write
(file, buf, count, &file->f_pos)。
static ssize_t
pipe_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
{
struct inode *inode = filp->f_dentry->d_inode;
ssize_t free, written, ret;
/* Seeks are not allowed on pipes. */
ret = -ESPIPE;
written = 0;
if (ppos != &filp->f_pos)
goto out_nolock;
/* Null write succeeds. */
ret = 0;
if (count == 0)
goto out_nolock;
ret = -ERESTARTSYS;
if (down_interruptible(PIPE_SEM(*inode)))
goto out_nolock;
/* No readers yields SIGPIPE. */
if (!PIPE_READERS(*inode))
goto sigpipe;
/* If count <= PIPE_BUF, we have to make it atomic. */
free = (count <= PIPE_BUF ? count : 1);//如果要写入的字节数大于整个缓冲区的大小,那么free为1
/* Wait, or check for, available space. */
if (filp->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
if (PIPE_FREE(*inode) < free)
goto out;
} else {
while (PIPE_FREE(*inode) < free) {//缓冲区剩余空间小于要写入的字节数,如果free为1,表示只要有一个字节的剩余空间,就不需要睡眠
PIPE_WAITING_WRITERS(*inode)++;//waiting_writers++
pipe_wait(inode);//那么就要睡眠等待
PIPE_WAITING_WRITERS(*inode)--;
ret = -ERESTARTSYS;
if (signal_pending(current))
goto out;
if (!PIPE_READERS(*inode))
goto sigpipe;
}
}
/* Copy into available space. */
ret = -EFAULT;
while (count > 0) {//如果缓冲区剩余空间大于要写入的字节数
int space;
char *pipebuf = PIPE_BASE(*inode) + PIPE_END(*inode);
ssize_t chars = PIPE_MAX_WCHUNK(*inode);
if ((space = PIPE_FREE(*inode)) != 0) {//如果没有剩余空间了,那么就只说明,要写的字节大于缓冲区的总大小,执行下面的do_while循环
if (chars > count)
chars = count;
if (chars > space)
chars = space;
if (copy_from_user(pipebuf, buf, chars))
goto out;
written += chars;
PIPE_LEN(*inode) += chars;
count -= chars;
buf += chars;
space = PIPE_FREE(*inode);
continue;//由于是缓冲区是一个循环的页面,如果一次写操作,跨过页面开始位置,要分两次写,continue如果count>0,就表示分两次写,如果count不大于0,说明分一次写,并且已经写完了
}
ret = written;
if (filp->f_flags & O_NONBLOCK)
break;
do {
/*
* Synchronous wake-up: it knows that this process
* is going to give up this CPU, so it doesnt have
* to do idle reschedules.
*/
wake_up_interruptible_sync(PIPE_WAIT(*inode));//唤醒读端进程
PIPE_WAITING_WRITERS(*inode)++;//waiting_writers++
pipe_wait(inode);//写端进程睡眠等待
PIPE_WAITING_WRITERS(*inode)--;
if (signal_pending(current))
goto out;
if (!PIPE_READERS(*inode))
goto sigpipe;
} while (!PIPE_FREE(*inode));//只要有一个字节的剩余空间,就退出do_while循环,再进行一次外部while循环
ret = -EFAULT;
}
/* Signal readers asynchronously that there is more data. */
wake_up_interruptible(PIPE_WAIT(*inode));//如果分一次写,分两次写,是不会执行上面的do_while循环的,但也要唤醒读端进程
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
mark_inode_dirty(inode);
out:
up(PIPE_SEM(*inode));
out_nolock:
if (written)
ret = written;
return ret;
sigpipe:
if (written)
goto out;
up(PIPE_SEM(*inode));
send_sig(SIGPIPE, current, 0);
return -EPIPE;
}
pipe_wait,睡眠等待,代码如下:
void pipe_wait(struct inode * inode)
{
DECLARE_WAITQUEUE(wait, current);//把当前进程的task_struct结构和wait_queue连在一起,见下面代码
current->state = TASK_INTERRUPTIBLE;//当前进程设置为可中断等待状态
add_wait_queue(PIPE_WAIT(*inode), &wait);//把wait加入到(inode).i_pipe->wait
up(PIPE_SEM(*inode));
schedule();//切换进程
remove_wait_queue(PIPE_WAIT(*inode), &wait);
current->state = TASK_RUNNING;
down(PIPE_SEM(*inode));
}
#define DECLARE_WAITQUEUE(wait, current) \
struct wait_queue wait = { current, NULL }
void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
{
unsigned long flags;
wq_write_lock_irqsave(&q->lock, flags);
wait->flags = 0;
__add_wait_queue(q, wait);
wq_write_unlock_irqrestore(&q->lock, flags);
}
static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new)
{
......
list_add(&new->task_list, &head->task_list);
}
总结一下:
1、如果剩余空间不足,那么就马上睡眠等待;
2、如果剩余空间足够,分一次写或者分两次写后,唤醒读端进程,程序返回;
3、如果剩余空间足够,但是要写入的字节数大于缓冲区大小,那么也要唤醒读端进程,并睡眠等待。
读和写都是往一个循环的页面,读和写内容的,如下图:
然后子进程开始执行,并且关闭了写端,执行read(fd[0],str2,strlen(str2)),映射到内核,sys_read,代码如下:
asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
{
ssize_t ret;
struct file * file;
ret = -EBADF;
file = fget(fd);
if (file) {
if (file->f_mode & FMODE_READ) {
ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
file, file->f_pos, count);
if (!ret) {
ssize_t (*read)(struct file *, char *, size_t, loff_t *);
ret = -EINVAL;
if (file->f_op && (read = file->f_op->read) != NULL)
ret = read(file, buf, count, &file->f_pos);//pipe_read
}
}
if (ret > 0)
inode_dir_notify(file->f_dentry->d_parent->d_inode,
DN_ACCESS);
fput(file);
}
return ret;
}
read(file, buf, count, &file->f_pos)指向pipe_read
(file, buf, count, &file->f_pos),代码如下:
static ssize_t
pipe_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
{
struct inode *inode = filp->f_dentry->d_inode;
ssize_t size, read, ret;
/* Seeks are not allowed on pipes. */
ret = -ESPIPE;
read = 0;
if (ppos != &filp->f_pos)
goto out_nolock;
/* Always return 0 on null read. */
ret = 0;
if (count == 0)
goto out_nolock;
/* Get the pipe semaphore */
ret = -ERESTARTSYS;
if (down_interruptible(PIPE_SEM(*inode)))
goto out_nolock;
if (PIPE_EMPTY(*inode)) {
do_more_read:
ret = 0;
if (!PIPE_WRITERS(*inode))
goto out;
ret = -EAGAIN;
if (filp->f_flags & O_NONBLOCK)
goto out;
for (;;) {//如果缓冲区没有字节可读,那么就睡眠等待
PIPE_WAITING_READERS(*inode)++;//waiting_readers++
pipe_wait(inode);
PIPE_WAITING_READERS(*inode)--;
ret = -ERESTARTSYS;
if (signal_pending(current))
goto out;
ret = 0;
if (!PIPE_EMPTY(*inode))
break;
if (!PIPE_WRITERS(*inode))
goto out;
}
}
/* Read what data is available. */
ret = -EFAULT;
while (count > 0 && (size = PIPE_LEN(*inode))) {//如果缓冲区中有字节,分一次或者两次读完缓冲区的字节
char *pipebuf = PIPE_BASE(*inode) + PIPE_START(*inode);
ssize_t chars = PIPE_MAX_RCHUNK(*inode);
if (chars > count)
chars = count;
if (chars > size)
chars = size;
if (copy_to_user(buf, pipebuf, chars))
goto out;
read += chars;
PIPE_START(*inode) += chars;
PIPE_START(*inode) &= (PIPE_SIZE - 1);
PIPE_LEN(*inode) -= chars;
count -= chars;
buf += chars;
}
/* Cache behaviour optimization */
if (!PIPE_LEN(*inode))
PIPE_START(*inode) = 0;
if (count && PIPE_WAITING_WRITERS(*inode) && !(filp->f_flags & O_NONBLOCK)) {//如果count大于0,并且有等待写的进程,那么说明count要读的字节数大于缓冲区现有的字节数,或者大于缓冲区的总大小,要睡眠等待,并唤醒写端进程
/*
* We know that we are going to sleep: signal
* writers synchronously that there is more
* room.
*/
wake_up_interruptible_sync(PIPE_WAIT(*inode));//唤醒写端进程
if (!PIPE_EMPTY(*inode))
BUG();
goto do_more_read;//返回到do_more_read睡眠等待
}
/* Signal writers asynchronously that there is more room. */
wake_up_interruptible(PIPE_WAIT(*inode));//如果count为0,说明分一次或者分两次读完了所需要的字节数,那么也要唤醒写端进程
ret = read;
out:
up(PIPE_SEM(*inode));
out_nolock:
if (read)
ret = read;
return ret;
}
总结一下:
1、如果没有可读的字节,那么就马上睡眠等待;
2、如果有可读的字节,分一次写或者分两次写后,唤醒写端进程,程序返回;
3、如果又可读的字节,但是要读入的字节数大于缓冲区现有的字节数,或者大于缓冲区的总大小,那么也要唤醒写端进程,并睡眠等待。