您的位置:首页 > 运维架构 > Linux

linux 有名管道FIFO

2013-07-01 23:01 405 查看
linux文件主要有4种:普通文件、目录文件、设备文件(字符设备文件/块设备文件)、管道文件

管道文件(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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: