//获取管道的inode结构 static struct inode * get_pipe_inode(void) { struct inode *inode = new_inode(pipe_mnt->mnt_sb); 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; /* * 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; }
//若现在的缓存区的数据长度为0 if (!buf->len) { buf->ops = NULL; ops->release(info, buf); curbuf = (curbuf + 1) & (PIPE_BUFFERS-1); info->curbuf = curbuf; info->nrbufs = --bufs; do_wakeup = 1; } total_len -= chars; //更新读的总长度 if (!total_len) //该读的已读完成 break; /* common path: read succeeded */ } if (bufs) /* More to do? */ continue; //若bufs为0,说明所有管道为NULL,此时进行一下操作 if (!PIPE_WRITERS(*inode)) //是否有写操作正在进行 break; if (!PIPE_WAITING_WRITERS(*inode)) { //是否需要等待 /* syscall merging: Usually we must not sleep * if O_NONBLOCK is set, or if we got some data. * But if a writer sleeps in kernel space, then * we can wait for that data without violating POSIX. */ if (ret) break; if (filp->f_flags & O_NONBLOCK) { //要等待但又设置了NONBLOCK标记,矛盾了 ret = -EAGAIN; break; } } if (signal_pending(current)) { //设置进程阻塞标志 if (!ret) ret = -ERESTARTSYS; break; } if (do_wakeup) { wake_up_interruptible_sync(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT); } pipe_wait(inode); } up(PIPE_SEM(*inode)); /* Signal writers asynchronously that there is more room. */ if (do_wakeup) { wake_up_interruptible(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT); } if (ret > 0) file_accessed(filp); //更新文件结构的atime对象 return ret; } static ssize_t pipe_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { struct iovec iov = { .iov_base = buf, .iov_len = count }; return pipe_readv(filp, &iov, 1, ppos); }
/* Drop the inode semaphore and wait for a pipe event, atomically */ void pipe_wait(struct inode * inode) { DEFINE_WAIT(wait); //把current添加到管道的等待队列中 prepare_to_wait(PIPE_WAIT(*inode), &wait, TASK_INTERRUPTIBLE); //释放i_sem up(PIPE_SEM(*inode)); schedule(); //被呼醒,把它从等待队列中删除 finish_wait(PIPE_WAIT(*inode), &wait); //再次获取i_sem索引节点信号量 down(PIPE_SEM(*inode)); }
if (!page) { page = alloc_page(GFP_HIGHUSER); if (unlikely(!page)) { ret = ret ? : -ENOMEM; break; } info->tmp_page = page; } /* Always wakeup, even if the copy fails. Otherwise * we lock up (O_NONBLOCK-)readers that sleep due to * syscall merging. * FIXME! Is this really true? */ do_wakeup = 1; chars = PAGE_SIZE; if (chars > total_len) chars = total_len;
//写chars字节到缓冲区中
error = pipe_iov_copy_from_user(kmap(page), iov, chars); kunmap(page); if (unlikely(error)) { if (!ret) ret = -EFAULT; break; } ret += chars;
/* Insert it into the buffer array */ /更新nrbufs,和len字段。 buf->page = page; buf->ops = &anon_pipe_buf_ops; buf->offset = 0; buf->len = chars; info->nrbufs = ++bufs; info->tmp_page = NULL;
//若没有写完继续写入剩下的数据
total_len -= chars; if (!total_len) break; } //还有可写缓冲区,继续写
if (bufs < PIPE_BUFFERS) continue; //若设置非阻塞,
//若没有写入任何的数据ret=0,此时返回错误
//若已经写完了数据,结束写操作。
if (filp->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; break; } if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; break; } if (do_wakeup) { wake_up_interruptible_sync(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN); do_wakeup = 0; } PIPE_WAITING_WRITERS(*inode)++; pipe_wait(inode); PIPE_WAITING_WRITERS(*inode)--; } out: up(PIPE_SEM(*inode)); if (do_wakeup) { wake_up_interruptible(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN); } if (ret > 0) inode_update_time(inode, 1); /* mtime and ctime */ return ret; }