Chinaunix首页 | 论坛 | 博客
  • 博客访问: 338914
  • 博文数量: 32
  • 博客积分: 1470
  • 博客等级: 上尉
  • 技术积分: 575
  • 用 户 组: 普通用户
  • 注册时间: 2006-05-31 11:38
个人简介

实践主义者,多行路远胜于多读书。

文章分类

分类: LINUX

2006-06-21 18:00:33

自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) |
给主人留下些什么吧!~~