mkfifo
Rev.2を表示中。最新版はこちら。
pipeはread/writeのみファイルですが、fifoはread/write/read_writeで、pipeで実装されてない1ファイルのread/writeが可能で、又多重openする事はdup2に相当します。サンプル
[root@localhost c]# cat fifo.c #include<stdio.h> #include<fcntl.h> #include<string.h> void read_fifo(int fd) { char buf[12]; memset(buf, 0, sizeof(buf)); read(fd, buf, 4); printf("%s\n", buf); } void main() { int fd1, fd2, fd3; fd1=open("fifo",O_RDWR); fd2=open("fifo",O_RDWR); fd3=open("fifo",O_RDWR); write(fd1,"12345", 5); write(fd2,"67890", 5); write(fd3,"abcde", 5); read_fifo(fd3); read_fifo(fd2); read_fifo(fd1); }
[root@localhost c]# mkfifo fifo [root@localhost c]# ls -l fifo prw-r--r-- 1 root root 0 10月 21 01:50 fifo [root@localhost c]# ./fifo.o 1234 5678 90abmkfifoのスペシャルファイルのdentryのinodeにinode->i_fop = &def_fifo_fopsとし、openがdef_fifo_fops.openコールされ、fileのread/writeコールバックをpipeのread/writeとする事で、ファイルによる読書でpipe読書きの実装となります。
mknodシステムコールからファイルシステム依存のmknodコールバック(ext3_mknod)で、inode->i_mode = S_IFIFO/inode->i_fop = &def_fifo_fopsとするinodeを作成します。このスペシャルファイルのinodeオープンでdef_fifo_fops.open=fifo_openがコールされ、下記の掛かるコールバックが設定されます。
READ : filp->f_op = &read_pipefifo_fops
WRITE : filp->f_op = &write_pipefifo_fops;
READ_WITE: filp->f_op = &rdwr_pipefifo_fops;
#define S_IFIFO 0010000 static int ext3_mknod (struct inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev) { handle_t *handle; struct inode *inode; int err, retries = 0; if (!new_valid_dev(rdev)) return -EINVAL; dquot_initialize(dir); retry: handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); if (IS_DIRSYNC(dir)) handle->h_sync = 1; inode = ext3_new_inode (handle, dir, &dentry->d_name, mode); err = PTR_ERR(inode); if (!IS_ERR(inode)) { init_special_inode(inode, inode->i_mode, rdev); err = ext3_add_nondir(handle, dentry, inode); } ext3_journal_stop(handle); if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) goto retry; return err; } const struct file_operations def_fifo_fops = { .open = fifo_open, .llseek = noop_llseek, }; void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev) { inode->i_mode = mode; if (S_ISCHR(mode)) { inode->i_fop = &def_chr_fops; inode->i_rdev = rdev; } else if (S_ISBLK(mode)) { inode->i_fop = &def_blk_fops; inode->i_rdev = rdev; } else if (S_ISFIFO(mode)) inode->i_fop = &def_fifo_fops; else if (S_ISSOCK(mode)) inode->i_fop = &bad_sock_fops; else printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for" " inode %s:%lu\n", mode, inode->i_sb->s_id, inode->i_ino); }pipeのinodeは、ブロックデバイスをメモリとするmount_pseudoでマウントされたpipefsファイルシステムのpipe管理情報を有するinodeで、引数のinodeはスペシャルファイルのinode故、alloc_pipe_info()でpipe情報のinode->i_pipe = pipeとされます。
static int fifo_open(struct inode *inode, struct file *filp) { struct pipe_inode_info *pipe; int ret; mutex_lock(&inode->i_mutex); pipe = inode->i_pipe; if (!pipe) { ret = -ENOMEM; pipe = alloc_pipe_info(inode); if (!pipe) goto err_nocleanup; inode->i_pipe = pipe; } filp->f_version = 0; filp->f_mode &= (FMODE_READ | FMODE_WRITE); switch (filp->f_mode) { case FMODE_READ: filp->f_op = &read_pipefifo_fops; pipe->r_counter++; if (pipe->readers++ == 0) wake_up_partner(inode); if (!pipe->writers) { if ((filp->f_flags & O_NONBLOCK)) { filp->f_version = pipe->w_counter; } else { wait_for_partner(inode, &pipe->w_counter); if(signal_pending(current)) goto err_rd; } } break; case FMODE_WRITE: ret = -ENXIO; if ((filp->f_flags & O_NONBLOCK) && !pipe->readers) goto err; filp->f_op = &write_pipefifo_fops; pipe->w_counter++; if (!pipe->writers++) wake_up_partner(inode); if (!pipe->readers) { wait_for_partner(inode, &pipe->r_counter); if (signal_pending(current)) goto err_wr; } break; case FMODE_READ | FMODE_WRITE: filp->f_op = &rdwr_pipefifo_fops; pipe->readers++; pipe->writers++; pipe->r_counter++; pipe->w_counter++; if (pipe->readers == 1 || pipe->writers == 1) wake_up_partner(inode); break; default: ret = -EINVAL; goto err; } mutex_unlock(&inode->i_mutex); return 0; err_rd: if (!--pipe->readers) wake_up_interruptible(&pipe->wait); ret = -ERESTARTSYS; goto err; err_wr: if (!--pipe->writers) wake_up_interruptible(&pipe->wait); ret = -ERESTARTSYS; goto err; err: if (!pipe->readers && !pipe->writers) free_pipe_info(inode); err_nocleanup: mutex_unlock(&inode->i_mutex); return ret; }