SPLICE(2) | Linux Programmer's Manual | SPLICE(2) |
名前¶
splice - パイプとの間でデータを継ぎ合わせる
書式¶
#define _GNU_SOURCE #include <fcntl.h> long splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags);
説明¶
splice() は、カーネルアドレス空間とユーザアドレス空間との間のコピーを伴わずに、 2 つのファイルディスクリプタ間でデータの移動を行う。 ファイルディスクリプタ fd_in からファイルディスクリプタ fd_out へ最大 len バイトを転送する。 2 つのファイルディスクリプタのうち一つは パイプを参照していなければならない。
fd_in がパイプを参照している場合、 off_in は NULL でなければならない。 fd_in がパイプを参照しておらず、 off_in が NULL の場合、 fd_in の現在のファイルオフセットから始まるバイトを読み出す。 現在のファイルオフセットは適切に調整される。 fd_in がパイプを参照しておらず、 off_in が NULL でない場合、 off_in は fd_in からのデータ読み出しを開始する先頭オフセットを格納したバッファ へのポインタでなければならない。この場合、 fd_in の現在のファイルオフセットは変更されない。 fd_out と off_out に関しても同様である。
flags 引き数には、以下の値の 0 個以上のビット単位の論理和を とったものを指定する:
- SPLICE_F_MOVE
- ページのコピーでなく移動を試みる。 これはカーネルに対するヒントでしかない。 つまり、カーネルがパイプからページを移動できない場合や、 パイプバッファがページ全部を参照していない場合は、 ページのコピーが行われることもある。 このフラグの最初の実装にはバグがあった。そのため、 Linux 2.6.21 以降ではこのフラグの操作はできないようになっている (ただし、 splice() コールでこのフラグを指定することは今も認められている)。 将来、正しい実装が行われることだろう。
- SPLICE_F_NONBLOCK
- 入出力時に停止 (block) しない。 このフラグを指定すると、 splice によるパイプ操作を非停止モード (non-blocking) で 行おうとするが、その場合でも splice() は停止することもある。なぜなら、データのやり取りを行う ファイルディスクリプタは (O_NONBLOCK フラグをセットされていない場合) 停止する可能性があるからである。
- SPLICE_F_MORE
- この後の splice でさらに転送されるデータがあることを示す。 このフラグは fd_out がソケットを参照している場合に有用なヒントとなる (send(2) の MSG_MORE や tcp(7) の TCP_CORK の説明も参照)。
- SPLICE_F_GIFT
- splice() では使用しない。 vmsplice(2) 参照。
返り値¶
成功して完了すると、 splice() はパイプから出し入れしたバイト数を返す。 返り値 0 はデータの転送が行わなかったことを示す。 この場合、処理を停止 (block) しても無意味である。 なぜなら、 fd_in が参照するパイプの書き込み側に接続されている者がいないからである。
エラーの場合、 splice() は -1 を返し、 errno にエラーを示す値を設定する。
エラー¶
バージョン¶
splice() システムコールは Linux 2.6.17 で初めて登場した。
準拠¶
このシステムコールは Linux 固有である。
注意¶
3 つのシステムコール (splice(), vmsplice(2), tee(2)) を使うと、ユーザ空間プログラムは任意のカーネルバッファに対する 完全な制御ができる。カーネルバッファは、パイプに使用されているのと 同種のバッファを使ってカーネル内に実装されている。 大まかにいうと、これらのシステムコールは以下の仕事を行う:
- splice()
- バッファから任意のファイルディスクリプタや、その逆方向、 もしくはあるバッファから別のバッファへの、データ移動を行う。
- tee(2)
- あるバッファから別のバッファへのデータ「コピー」を行う。
- vmsplice(2)
- ユーザ空間からバッファへのデータ「コピー」を行う。
ここではコピーの話をしているが、実際のコピーは一般的に回避される。 カーネルは、パイプ・バッファをカーネルメモリのページへのポインタ集合として 実装し、ページへの参照回数を管理することで、これを実現している。 カーネルは、対象となるページを参照する (出力バッファ用の) ポインタを 新規に作成することでバッファ内のページの「コピー」を作成し、 そのページの参照回数を増やす。つまり、ポインタだけがコピーされ、 バッファのページはコピーされない。
例¶
tee(2) 参照。
関連項目¶
2009-02-20 | Linux |