- 2007-05-18 (Fri) 3:16
- Unix

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, &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, &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, &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
-
あーそうだね。直すー。どもども。
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
