LoginSignup
2
1

More than 5 years have passed since last update.

システム間通信 パイプの実装について調べた

Posted at

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_infostruct 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
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1