Home > Unix > spliceシステムコールの使い方

spliceシステムコールの使い方

  • 2007-05-18 (Fri) 3:16
  • Unix
  • hatena button
  • hatena count
  • save this page del.icio.us

Linux 2.6.17より導入された新しいシステムコールである「splice(2)」を使ったファイルコピープログラムを作ってみました。
参考: C言語: UNIX最速ファイルコピー
参考: splice(2) - splice data to/from a pipe

試した環境は以下の通りです。

core2% uname -a
Linux core2 2.6.20-15-generic #2 SMP Sun Apr 15 06:17:24 UTC 2007 x86_64 GNU/Linux
gcc: Ubuntu 4.1.2-0ubuntu4
glibc version: 2.5-0ubuntu14

「splice」という単語は「つなぎ合わせる」とかいう意味です。このシステムコールも、ファイルディスクリプタとパイプをつなぎ合わせてデータを転送するような操作を行う事ができます。

調べていると、Wikipediaにコードが有ったのですが、何箇所か気になる所が有ったので直しながら書いてみました。


#include <sys/types.h>
#include <asm/unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#define __USE_GNU
#include <fcntl.h>
#undef __USE_GNU

static int
splice_copy(int srcfd, size_t size, int destfd)
{
  int r;
  int pipedes[2];
  r = pipe(pipedes);
  assert(r >= 0);
  int pipe_r = pipedes[0];
  int pipe_w = pipedes[1];
  size_t written;
  written = 0;
  while (written < size) {
    loff_t off_in = written;
    ssize_t nbytes = splice(srcfd, &amp;off_in, pipe_w, NULL, size - written,
                            SPLICE_F_MORE | SPLICE_F_MOVE);
    assert(nbytes >= 0);
    written += nbytes;
  }
  written = 0;
  while (written < size) {
    loff_t off_out = written;
    ssize_t nbytes = splice(pipe_r, NULL, destfd, &amp;off_out, size - written,
                            SPLICE_F_MORE | SPLICE_F_MOVE);
    assert(nbytes >= 0);
    written += nbytes;
  }
  close(pipe_r);
  close(pipe_w);
  return 0;
}
int
main(int argc, char **argv)
{
  int r;
  struct stat st_buf;
  if (argc < 3) {
    fprintf(stderr, "usage: %s src out\n", argv[0]);
    return 0;
  }
  char *src  = argv[1];
  char *dest = argv[2];
  assert(strcmp(src, dest) != 0);
  int srcfd = open(src, O_RDONLY, 0644);
  assert(srcfd >= 0);
#if USE_FADVISE
  posix_fadvise(srcfd, 0, 0, POSIX_FADV_SEQUENTIAL);
  posix_fadvise(srcfd, 0, 0, POSIX_FADV_NOREUSE);
#endif
  /* get permission */
  r = fstat(srcfd, &amp;st_buf);
  assert(r >= 0);
  int destfd = open(dest, O_WRONLY | O_CREAT, st_buf.st_mode);
  assert(destfd >= 0);
  r = splice_copy(srcfd, st_buf.st_size, destfd);
  assert(r == 0);
  fsync(destfd);
  close(destfd);
  close(srcfd);
  return 0;
}

コードを眺めていると、ファイルディスクリプタがカーネルバッファーへのポインタの様に思えてきます。つまりsplice(2)はカーネルバッファーに対するread(2)やwrite(2)の様なものと説明すると分かりやすいのかな。

sendfile(2)も似たようなものなのですが、sendfile(2)はoutにsocketしか取れないという点が異なっていますね。
カーネルの方の確認 & 速度検証をしたらUNIX最速ファイルコピーの方のデータも更新します。

Similar Posts:

Comments:2

nya 07-05-18 (Fri) 11:04

assertのなかに副作用コードを書くのはあぶなくない?

kzk 07-05-18 (Fri) 11:50

あーそうだね。直すー。どもども。

Comment Form
Remember personal info

Trackbacks:0

Trackback URL for this entry
http://kzk9.net/blog/2007/05/splice2.html/trackback
Listed below are links to weblogs that reference
spliceシステムコールの使い方 from moratorium

Home > Unix > spliceシステムコールの使い方

お薦め本
広告
Archives
Categories

Return to page top