linux 有名管道FIFO
2013-07-01 23:01
405 查看
linux文件主要有4种:普通文件、目录文件、设备文件(字符设备文件/块设备文件)、管道文件
管道文件(p表示管道文件)
文件系统(ext4/ext3/nfs)中存在管道文件,所以就通过文件名称来标识管道文件及其关联的管道FIFO;所以有名管道就可以在非亲子关系的进程间实现通信,一个进程通过文件名打开管道的写端,另一个进程通过文件名打开管道的读端,两个进程就可以通过该FIFO实现通信。
I.def_fifo_fops
def_fifo_fops表示管道文件的操作集,定义如下:
当打开管道文件时会触发def_fifo_fops中的open方法fifo_open,代码跟踪如下:
文件方法集:
open->do_sys_open->do_filp_open->path_lookup_open->do_path_lookup->path_walk->link_path_walk->__link_path_walk->do_lookup->real_lookup
ext4为例:
ext4_lookup->ext4_iget->init_special_inode->def_fifo_fops
open回调:
open->do_sys_open->do_filp_open->nameidata_to_filp->__dentry_open->fifo_open
II.fifo_open
1.获取管道互斥锁,进入管道操作临界区
2.如果文件未与管道关联,则创建管道并将管道文件与管道关联起来
3.判断文件的打开方式:
*如果是只读方式打开管道文件
A.将管道文件操作赋为read_pipefifo_fops,即只读管道不能有写管道操作,否则报错EBADF
B.管道读者计数器加1
C.管道当前读者计数器加1,如果以前没有读者,则尝试唤醒被阻塞的写者进程
D.如果管道没有写者进程
a.如果文件以NONBLOCK方式打开,则同步f_version与w_counter,用于抑制POLLHUP直到有写者出现
b.否则阻塞读者进程,直到有写者进程出现或有信号产生;如果是产生信号而被唤醒,则管道当前读者计数器减1,如果没有读者了则唤醒管道中被阻塞的进程,并返回ERESTARTSYS,内核处理完信号后再自动重启open;如果是有写者进程出现而被唤醒,则正常返回
*如果是只写方式打开管道文件
A.如果以NONBLOCK方式打开管道文件,且管道没有读者,则返回ENXIO错误
B.将管道文件操作赋为write_pipefifo_fops,即只写管道不能有读管道操作,否则报错EBADF
C.管道写者计数器加1
D.管道当前写者计数器加1,如果以前没有写者,则尝试唤醒被阻塞的读者进程
E.如果管道没有读者进程,阻塞写者进程,直到有读者进程出现或有信号产生;如果是产生信号而被唤醒,则管道当前写者计数器减1,如果没有写者了则唤醒管道中被阻塞的进程,并返回ERESTARTSYS,内核处理完信号后再自动重启open;如果是有读者进程出现而被唤醒,则正常返回
*如果是读写方式打开管道文件
B.将管道文件操作赋为rdwr_pipefifo_fops,表示管道既能写也能读
B.将管道当前读者计数器,管道当前写者计数器,管道读者计数器,管道写者计数器分别加1
C.如果以前没有读者/写者,尝试唤醒被阻塞的写者/读者进程
4.释放管道互斥锁,即出管道操作临界区
管道的read,write,poll,fcntl,ioctl操作见linux pipe文件系统(pipefs)
管道文件(p表示管道文件)
[redhat@localhost tmp]$ mkfifo fifo [redhat@localhost tmp]$ ll fifo prw-rw-r--. 1 redhat redhat 0 7月 1 22:06 fifo
文件系统(ext4/ext3/nfs)中存在管道文件,所以就通过文件名称来标识管道文件及其关联的管道FIFO;所以有名管道就可以在非亲子关系的进程间实现通信,一个进程通过文件名打开管道的写端,另一个进程通过文件名打开管道的读端,两个进程就可以通过该FIFO实现通信。
I.def_fifo_fops
def_fifo_fops表示管道文件的操作集,定义如下:
/* fs/fifo.c */ 148 /* 149 * Dummy default file-operations: the only thing this does 150 * is contain the open that then fills in the correct operations 151 * depending on the access mode of the file... 152 */ 153 const struct file_operations def_fifo_fops = { 154 .open = fifo_open, /* will set read_ or write_pipefifo_fops */ 155 };
当打开管道文件时会触发def_fifo_fops中的open方法fifo_open,代码跟踪如下:
文件方法集:
open->do_sys_open->do_filp_open->path_lookup_open->do_path_lookup->path_walk->link_path_walk->__link_path_walk->do_lookup->real_lookup
ext4为例:
ext4_lookup->ext4_iget->init_special_inode->def_fifo_fops
open回调:
open->do_sys_open->do_filp_open->nameidata_to_filp->__dentry_open->fifo_open
II.fifo_open
18 static void wait_for_partner(struct inode* inode, unsigned int *cnt) 19 { 20 int cur = *cnt; 21 22 while (cur == *cnt) { 23 pipe_wait(inode->i_pipe); 24 if (signal_pending(current)) 25 break; 26 } 27 } 28 29 static void wake_up_partner(struct inode* inode) 30 { 31 wake_up_interruptible(&inode->i_pipe->wait); 32 } 33 34 static int fifo_open(struct inode *inode, struct file *filp) 35 { 36 struct pipe_inode_info *pipe; 37 int ret; 38 39 mutex_lock(&inode->i_mutex); 40 pipe = inode->i_pipe; 41 if (!pipe) { 42 ret = -ENOMEM; 43 pipe = alloc_pipe_info(inode); 44 if (!pipe) 45 goto err_nocleanup; 46 inode->i_pipe = pipe; 47 } 48 filp->f_version = 0; 49 50 /* We can only do regular read/write on fifos */ 51 filp->f_mode &= (FMODE_READ | FMODE_WRITE); 52 53 switch (filp->f_mode) { 54 case FMODE_READ: 55 /* 56 * O_RDONLY 57 * POSIX.1 says that O_NONBLOCK means return with the FIFO 58 * opened, even when there is no process writing the FIFO. 59 */ 60 filp->f_op = &read_pipefifo_fops; 61 pipe->r_counter++; 62 if (pipe->readers++ == 0) 63 wake_up_partner(inode); 64 65 if (!pipe->writers) { 66 if ((filp->f_flags & O_NONBLOCK)) { 67 /* suppress POLLHUP until we have 68 * seen a writer */ 69 filp->f_version = pipe->w_counter; 70 } else 71 { 72 wait_for_partner(inode, &pipe->w_counter); 73 if(signal_pending(current)) 74 goto err_rd; 75 } 76 } 77 break; 78 79 case FMODE_WRITE: 80 /* 81 * O_WRONLY 82 * POSIX.1 says that O_NONBLOCK means return -1 with 83 * errno=ENXIO when there is no process reading the FIFO. 84 */ 85 ret = -ENXIO; 86 if ((filp->f_flags & O_NONBLOCK) && !pipe->readers) 87 goto err; 88 89 filp->f_op = &write_pipefifo_fops; 90 pipe->w_counter++; 91 if (!pipe->writers++) 92 wake_up_partner(inode); 93 94 if (!pipe->readers) { 95 wait_for_partner(inode, &pipe->r_counter); 96 if (signal_pending(current)) 97 goto err_wr; 98 } 99 break; 100 101 case FMODE_READ | FMODE_WRITE: 102 /* 103 * O_RDWR 104 * POSIX.1 leaves this case "undefined" when O_NONBLOCK is set. 105 * This implementation will NEVER block on a O_RDWR open, since 106 * the process can at least talk to itself. 107 */ 108 filp->f_op = &rdwr_pipefifo_fops; 109 110 pipe->readers++; 111 pipe->writers++; 112 pipe->r_counter++; 113 pipe->w_counter++; 114 if (pipe->readers == 1 || pipe->writers == 1) 115 wake_up_partner(inode); 116 break; 117 118 default: 119 ret = -EINVAL; 120 goto err; 121 } 122 123 /* Ok! */ 124 mutex_unlock(&inode->i_mutex); 125 return 0; 126 127 err_rd: 128 if (!--pipe->readers) 124 mutex_unlock(&inode->i_mutex); 125 return 0; 126 127 err_rd: 128 if (!--pipe->readers) 129 wake_up_interruptible(&pipe->wait); 130 ret = -ERESTARTSYS; 131 goto err; 132 133 err_wr: 134 if (!--pipe->writers) 135 wake_up_interruptible(&pipe->wait); 136 ret = -ERESTARTSYS; 137 goto err; 138 139 err: 140 if (!pipe->readers && !pipe->writers) 141 free_pipe_info(inode); 142 143 err_nocleanup: 144 mutex_unlock(&inode->i_mutex); 145 return ret; 146 } 147
1.获取管道互斥锁,进入管道操作临界区
2.如果文件未与管道关联,则创建管道并将管道文件与管道关联起来
3.判断文件的打开方式:
*如果是只读方式打开管道文件
A.将管道文件操作赋为read_pipefifo_fops,即只读管道不能有写管道操作,否则报错EBADF
B.管道读者计数器加1
C.管道当前读者计数器加1,如果以前没有读者,则尝试唤醒被阻塞的写者进程
D.如果管道没有写者进程
a.如果文件以NONBLOCK方式打开,则同步f_version与w_counter,用于抑制POLLHUP直到有写者出现
b.否则阻塞读者进程,直到有写者进程出现或有信号产生;如果是产生信号而被唤醒,则管道当前读者计数器减1,如果没有读者了则唤醒管道中被阻塞的进程,并返回ERESTARTSYS,内核处理完信号后再自动重启open;如果是有写者进程出现而被唤醒,则正常返回
*如果是只写方式打开管道文件
A.如果以NONBLOCK方式打开管道文件,且管道没有读者,则返回ENXIO错误
B.将管道文件操作赋为write_pipefifo_fops,即只写管道不能有读管道操作,否则报错EBADF
C.管道写者计数器加1
D.管道当前写者计数器加1,如果以前没有写者,则尝试唤醒被阻塞的读者进程
E.如果管道没有读者进程,阻塞写者进程,直到有读者进程出现或有信号产生;如果是产生信号而被唤醒,则管道当前写者计数器减1,如果没有写者了则唤醒管道中被阻塞的进程,并返回ERESTARTSYS,内核处理完信号后再自动重启open;如果是有读者进程出现而被唤醒,则正常返回
*如果是读写方式打开管道文件
B.将管道文件操作赋为rdwr_pipefifo_fops,表示管道既能写也能读
B.将管道当前读者计数器,管道当前写者计数器,管道读者计数器,管道写者计数器分别加1
C.如果以前没有读者/写者,尝试唤醒被阻塞的写者/读者进程
4.释放管道互斥锁,即出管道操作临界区
管道的read,write,poll,fcntl,ioctl操作见linux pipe文件系统(pipefs)
相关文章推荐
- linux进程通信--有名管道(FIFO)(含实例代码)
- linux 无名管道pipe和有名管道FIFO
- linux fifo 有名管道
- Linux--进程间通信(管道及有名管道FIFO)(转)
- Linux系统编程:fifo有名管道的使用
- (转)linux 无名管道pipe和有名管道FIFO
- linux16.04 中创建 有名管道 fifo
- Linux有名管道(FIFO)的阻塞和非阻塞读写
- linux 有名管道FIFO的一点理解
- linux编程---进程间通信---FIFO---有名管道
- linux 有名管道(FIFO)
- Linux进程间通信二--有名管道FIFO
- linux下c编程系统调用之有名管道FIFO函数的使用及案例
- linux 有名管道(FIFO)
- linuxFIFO(有名管道)
- Linux C 编程----有名管道FIFO
- linux进程间通信-有名管道(FIFO)
- 嵌入式 Linux环境进程间通信(二):有名管道(FIFO)
- (转)linux 无名管道pipe和有名管道FIFO
- linux 进程编程:有名管道fifo