Linuxのパイプの実装について調べた。
カーネルバージョン
v4.5.0
パイプ、名前付きパイプとは
VFSのオペレーションで扱うことが出来る、メモリ上の一時ファイルみたいなもの。
pipefsに作られる場合は普通のパイプで、ファイルシステム上に次のoperationを持って作られた場合、名前付きパイプと呼ぶ。要するにinodeがどこから辿れるか、という違いだけで内部の実装はおなじ。
const struct file_operations pipefifo_fops = {
.open = fifo_open,
.llseek = no_llseek,
.read_iter = pipe_read,
.write_iter = pipe_write,
.poll = pipe_poll,
.unlocked_ioctl = pipe_ioctl,
.release = pipe_release,
.fasync = pipe_fasync,
};
パイプの作成はpipeシステムコールの延長の、__do_pipe_flags()
によって行われる。
inode番号は、get_next_ino()
によって確保される。CONFIG_SMPの場合、CPUごとにプールを作ったりしているが、要するにシステム全体でインクリメントしていく数を順番に割り当てているだけである。オーバーフローすると重複するが、パイプはfdでやり取りされるだけなので、問題ないのだろう。
unsigned int get_next_ino(void)
{
unsigned int *p = &get_cpu_var(last_ino);
unsigned int res = *p;
#ifdef CONFIG_SMP
if (unlikely((res & (LAST_INO_BATCH-1)) == 0)) {
static atomic_t shared_last_ino;
int next = atomic_add_return(LAST_INO_BATCH, &shared_last_ino);
res = next - LAST_INO_BATCH;
}
#endif
res++;
/* get_next_ino should not provide a 0 inode number */
if (unlikely(!res))
res++;
*p = res;
put_cpu_var(last_ino);
return res;
}
EXPORT_SYMBOL(get_next_ino);
ちなみに、パイプのファイル名を参照すると、pipe:[inode番号]
のような表示になる。
juntaki@lab% sleep 100 | cat &
[2] 1822 1823
juntaki@lab% ls -la /proc/1822/fd
total 0
dr-x------ 2 juntaki juntaki 0 4月 10 15:09 .
dr-xr-xr-x 9 juntaki juntaki 0 4月 10 15:09 ..
lrwx------ 1 juntaki juntaki 64 4月 10 15:09 0 -> /dev/pts/3
l-wx------ 1 juntaki juntaki 64 4月 10 15:09 1 -> pipe:[10810]
lrwx------ 1 juntaki juntaki 64 4月 10 15:09 2 -> /dev/pts/3
pipefsは外部から参照されないので、パス名は不要なためである。
pipefs_dname()
で生成している。
static char *pipefs_dname(struct dentry *dentry, char *buffer, int buflen)
{
return dynamic_dname(dentry, buffer, buflen, "pipe:[%lu]",
d_inode(dentry)->i_ino);
}
パイプバッファ
パイプを書き込んでから別のプロセスが受け取るまでの間、データを置いておくのがパイプバッファである。
pipe_inode_info
のstruct pipe_buffer *bufs
からポイントされる場所にある。サイズはalloc_pipe_info()
で初期化され、サイズはPIPE_DEF_BUFFERS * 4KB = 64KB
となる。
struct pipe_buffer {
struct page *page;
unsigned int offset, len;
const struct pipe_buf_operations *ops;
unsigned int flags;
unsigned long private;
};
#define PIPE_DEF_BUFFERS 16