自linux2.6.17版本起,内核增加了两个新的系统调用:
asmlinkage long sys_tee(int fdin, int fdout, size_t len, unsigned int flags);
asmlinkage long sys_splice(int fd_in, loff_t __user *off_in,
int fd_out, loff_t __user *off_out,
size_t len, unsigned int flags);
根拒内核文档的描述,该两个系统调用可以解决传统的应用层数据拷贝时的效率问题,很多情况下我们需要写如下的代码来完成应用层的数据拷贝:
/*
* 伪代码格式.
*/
while(read(buff) > 0)
{
write(buff);
}
采用以上方式完成一次数据拷贝过程,需要由内核将buff数据拷贝至应用层,再由应用层拷贝回内核,其实是非常影响效率的,特别是当在应用层做文件拷贝或应用层的网络数据转发时.
而使用内核中新的系统调用tee()则直接在内核处复制内存页面,变得非常简单,内核中的描述原文如下:
This is a tee(1) implementation that works on pipes. It doesn't copy any data, it simply references the 'in' pages on the 'out' pipe. The 'flags' used are the SPLICE_F_* variants, currently the only applicable one is SPLICE_F_NONBLOCK.
使用以下代码可以测试tee()的功能,但很遗憾的是我在2.6.17-rc3的内核中测试是不成功的:
/*
* A tee implementation using sys_tee.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#if defined(__i386__)
#define __NR_splice 313
#define __NR_tee 315
#elif defined(__x86_64__)
#define __NR_splice 275
#define __NR_tee 276
#elif defined(__powerpc__) || defined(__powerpc64__)
#define __NR_splice 283
#define __NR_tee 284
#else
#error unsupported arch
#endif
#define SPLICE_F_NONBLOCK (0x02)
static inline int splice(int fdin, loff_t *off_in, int fdout, loff_t *off_out,
size_t len, unsigned int flags)
{
return syscall(__NR_splice, fdin, off_in, fdout, off_out, len, flags);
}
static inline int tee(int fdin, int fdout, size_t len, unsigned int flags)
{
return syscall(__NR_tee, fdin, fdout, len, flags);
}
static int error(const char *n)
{
perror(n);
return -1;
}
static int do_splice(int infd, int outfd, unsigned int len, char *msg)
{
while (len) {
int written = splice(infd, NULL, outfd, NULL, len, 0);
if (written <= 0)
return error(msg);
len -= written;
}
return 0;
}
int main(int argc, char *argv[])
{
struct stat sb;
int fd;
if (argc < 2) {
fprintf(stderr, "%s: outfile\n", argv[0]);
return 1;
}
if (fstat(STDIN_FILENO, &sb) < 0)
return error("stat");
if (!S_ISFIFO(sb.st_mode)) {
fprintf(stderr, "stdout must be a pipe\n");
return 1;
}
fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd < 0)
return error("open output");
do {
int tee_len = tee(STDIN_FILENO, STDOUT_FILENO, INT_MAX, SPLICE_F_NONBLOCK);
if (tee_len < 0) {
if (errno == EAGAIN) {
usleep(1000);
continue;
}
return error("tee");
} else if (!tee_len)
break;
/*
* Send output to file, also consumes input pipe.
*/
if (do_splice(STDIN_FILENO, fd, tee_len, "splice-file"))
break;
} while (1);
return 0;
}
关于splice()还不明白其作用,欢迎一起来讨论...
阅读(2245) | 评论(0) | 转发(0) |