From 3f525d41c2acde2ae3309cf839d83d7f41ab2fe6 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 24 Jun 2014 16:32:01 -0700 Subject: [PATCH] Add splice, tee, and vmsplice. Change-Id: I5f43380b88d776a8bb607b47dbbc5db5a2fe6163 --- libc/SYSCALLS.TXT | 4 ++ libc/arch-arm/syscalls/splice.S | 22 ++++++++ libc/arch-arm/syscalls/tee.S | 14 +++++ libc/arch-arm/syscalls/vmsplice.S | 14 +++++ libc/arch-arm64/syscalls/splice.S | 14 +++++ libc/arch-arm64/syscalls/tee.S | 14 +++++ libc/arch-arm64/syscalls/vmsplice.S | 14 +++++ libc/arch-mips/syscalls/splice.S | 19 +++++++ libc/arch-mips/syscalls/tee.S | 19 +++++++ libc/arch-mips/syscalls/vmsplice.S | 19 +++++++ libc/arch-mips64/syscalls/splice.S | 25 +++++++++ libc/arch-mips64/syscalls/tee.S | 25 +++++++++ libc/arch-mips64/syscalls/vmsplice.S | 25 +++++++++ libc/arch-x86/syscalls/splice.S | 46 +++++++++++++++ libc/arch-x86/syscalls/tee.S | 36 ++++++++++++ libc/arch-x86/syscalls/vmsplice.S | 36 ++++++++++++ libc/arch-x86_64/syscalls/splice.S | 16 ++++++ libc/arch-x86_64/syscalls/tee.S | 16 ++++++ libc/arch-x86_64/syscalls/vmsplice.S | 16 ++++++ libc/include/fcntl.h | 13 ++++- tests/fcntl_test.cpp | 84 ++++++++++++++++++++++++++++ 21 files changed, 488 insertions(+), 3 deletions(-) create mode 100644 libc/arch-arm/syscalls/splice.S create mode 100644 libc/arch-arm/syscalls/tee.S create mode 100644 libc/arch-arm/syscalls/vmsplice.S create mode 100644 libc/arch-arm64/syscalls/splice.S create mode 100644 libc/arch-arm64/syscalls/tee.S create mode 100644 libc/arch-arm64/syscalls/vmsplice.S create mode 100644 libc/arch-mips/syscalls/splice.S create mode 100644 libc/arch-mips/syscalls/tee.S create mode 100644 libc/arch-mips/syscalls/vmsplice.S create mode 100644 libc/arch-mips64/syscalls/splice.S create mode 100644 libc/arch-mips64/syscalls/tee.S create mode 100644 libc/arch-mips64/syscalls/vmsplice.S create mode 100644 libc/arch-x86/syscalls/splice.S create mode 100644 libc/arch-x86/syscalls/tee.S create mode 100644 libc/arch-x86/syscalls/vmsplice.S create mode 100644 libc/arch-x86_64/syscalls/splice.S create mode 100644 libc/arch-x86_64/syscalls/tee.S create mode 100644 libc/arch-x86_64/syscalls/vmsplice.S diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT index 839cfb7f4..b4c81341d 100644 --- a/libc/SYSCALLS.TXT +++ b/libc/SYSCALLS.TXT @@ -285,6 +285,10 @@ int klogctl:syslog(int, char*, int) all int sysinfo(struct sysinfo*) all int personality(unsigned long) all +ssize_t tee(int, int, size_t, unsigned int) all +ssize_t splice(int, off64_t*, int, off64_t*, size_t, unsigned int) all +ssize_t vmsplice(int, const struct iovec*, size_t, unsigned int) all + int epoll_create1(int) all int epoll_ctl(int, int op, int, struct epoll_event*) all int __epoll_pwait:epoll_pwait(int, struct epoll_event*, int, int, const sigset_t*, size_t) all diff --git a/libc/arch-arm/syscalls/splice.S b/libc/arch-arm/syscalls/splice.S new file mode 100644 index 000000000..782ba6c6f --- /dev/null +++ b/libc/arch-arm/syscalls/splice.S @@ -0,0 +1,22 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +ENTRY(splice) + mov ip, sp + stmfd sp!, {r4, r5, r6, r7} + .cfi_def_cfa_offset 16 + .cfi_rel_offset r4, 0 + .cfi_rel_offset r5, 4 + .cfi_rel_offset r6, 8 + .cfi_rel_offset r7, 12 + ldmfd ip, {r4, r5, r6} + ldr r7, =__NR_splice + swi #0 + ldmfd sp!, {r4, r5, r6, r7} + .cfi_def_cfa_offset 0 + cmn r0, #(MAX_ERRNO + 1) + bxls lr + neg r0, r0 + b __set_errno +END(splice) diff --git a/libc/arch-arm/syscalls/tee.S b/libc/arch-arm/syscalls/tee.S new file mode 100644 index 000000000..91746176b --- /dev/null +++ b/libc/arch-arm/syscalls/tee.S @@ -0,0 +1,14 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +ENTRY(tee) + mov ip, r7 + ldr r7, =__NR_tee + swi #0 + mov r7, ip + cmn r0, #(MAX_ERRNO + 1) + bxls lr + neg r0, r0 + b __set_errno +END(tee) diff --git a/libc/arch-arm/syscalls/vmsplice.S b/libc/arch-arm/syscalls/vmsplice.S new file mode 100644 index 000000000..3b8962310 --- /dev/null +++ b/libc/arch-arm/syscalls/vmsplice.S @@ -0,0 +1,14 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +ENTRY(vmsplice) + mov ip, r7 + ldr r7, =__NR_vmsplice + swi #0 + mov r7, ip + cmn r0, #(MAX_ERRNO + 1) + bxls lr + neg r0, r0 + b __set_errno +END(vmsplice) diff --git a/libc/arch-arm64/syscalls/splice.S b/libc/arch-arm64/syscalls/splice.S new file mode 100644 index 000000000..103805ac6 --- /dev/null +++ b/libc/arch-arm64/syscalls/splice.S @@ -0,0 +1,14 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +ENTRY(splice) + mov x8, __NR_splice + svc #0 + + cmn x0, #(MAX_ERRNO + 1) + cneg x0, x0, hi + b.hi __set_errno + + ret +END(splice) diff --git a/libc/arch-arm64/syscalls/tee.S b/libc/arch-arm64/syscalls/tee.S new file mode 100644 index 000000000..d730076f6 --- /dev/null +++ b/libc/arch-arm64/syscalls/tee.S @@ -0,0 +1,14 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +ENTRY(tee) + mov x8, __NR_tee + svc #0 + + cmn x0, #(MAX_ERRNO + 1) + cneg x0, x0, hi + b.hi __set_errno + + ret +END(tee) diff --git a/libc/arch-arm64/syscalls/vmsplice.S b/libc/arch-arm64/syscalls/vmsplice.S new file mode 100644 index 000000000..b4bec3f1e --- /dev/null +++ b/libc/arch-arm64/syscalls/vmsplice.S @@ -0,0 +1,14 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +ENTRY(vmsplice) + mov x8, __NR_vmsplice + svc #0 + + cmn x0, #(MAX_ERRNO + 1) + cneg x0, x0, hi + b.hi __set_errno + + ret +END(vmsplice) diff --git a/libc/arch-mips/syscalls/splice.S b/libc/arch-mips/syscalls/splice.S new file mode 100644 index 000000000..d344a6c9e --- /dev/null +++ b/libc/arch-mips/syscalls/splice.S @@ -0,0 +1,19 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +ENTRY(splice) + .set noreorder + .cpload t9 + li v0, __NR_splice + syscall + bnez a3, 1f + move a0, v0 + j ra + nop +1: + la t9,__set_errno + j t9 + nop + .set reorder +END(splice) diff --git a/libc/arch-mips/syscalls/tee.S b/libc/arch-mips/syscalls/tee.S new file mode 100644 index 000000000..e51732dcf --- /dev/null +++ b/libc/arch-mips/syscalls/tee.S @@ -0,0 +1,19 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +ENTRY(tee) + .set noreorder + .cpload t9 + li v0, __NR_tee + syscall + bnez a3, 1f + move a0, v0 + j ra + nop +1: + la t9,__set_errno + j t9 + nop + .set reorder +END(tee) diff --git a/libc/arch-mips/syscalls/vmsplice.S b/libc/arch-mips/syscalls/vmsplice.S new file mode 100644 index 000000000..24da5159e --- /dev/null +++ b/libc/arch-mips/syscalls/vmsplice.S @@ -0,0 +1,19 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +ENTRY(vmsplice) + .set noreorder + .cpload t9 + li v0, __NR_vmsplice + syscall + bnez a3, 1f + move a0, v0 + j ra + nop +1: + la t9,__set_errno + j t9 + nop + .set reorder +END(vmsplice) diff --git a/libc/arch-mips64/syscalls/splice.S b/libc/arch-mips64/syscalls/splice.S new file mode 100644 index 000000000..d6269040a --- /dev/null +++ b/libc/arch-mips64/syscalls/splice.S @@ -0,0 +1,25 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +ENTRY(splice) + .set push + .set noreorder + li v0, __NR_splice + syscall + bnez a3, 1f + move a0, v0 + j ra + nop +1: + move t0, ra + bal 2f + nop +2: + .cpsetup ra, t1, 2b + LA t9,__set_errno + .cpreturn + j t9 + move ra, t0 + .set pop +END(splice) diff --git a/libc/arch-mips64/syscalls/tee.S b/libc/arch-mips64/syscalls/tee.S new file mode 100644 index 000000000..429700c62 --- /dev/null +++ b/libc/arch-mips64/syscalls/tee.S @@ -0,0 +1,25 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +ENTRY(tee) + .set push + .set noreorder + li v0, __NR_tee + syscall + bnez a3, 1f + move a0, v0 + j ra + nop +1: + move t0, ra + bal 2f + nop +2: + .cpsetup ra, t1, 2b + LA t9,__set_errno + .cpreturn + j t9 + move ra, t0 + .set pop +END(tee) diff --git a/libc/arch-mips64/syscalls/vmsplice.S b/libc/arch-mips64/syscalls/vmsplice.S new file mode 100644 index 000000000..aa03585d0 --- /dev/null +++ b/libc/arch-mips64/syscalls/vmsplice.S @@ -0,0 +1,25 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +ENTRY(vmsplice) + .set push + .set noreorder + li v0, __NR_vmsplice + syscall + bnez a3, 1f + move a0, v0 + j ra + nop +1: + move t0, ra + bal 2f + nop +2: + .cpsetup ra, t1, 2b + LA t9,__set_errno + .cpreturn + j t9 + move ra, t0 + .set pop +END(vmsplice) diff --git a/libc/arch-x86/syscalls/splice.S b/libc/arch-x86/syscalls/splice.S new file mode 100644 index 000000000..46e231275 --- /dev/null +++ b/libc/arch-x86/syscalls/splice.S @@ -0,0 +1,46 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +ENTRY(splice) + pushl %ebx + .cfi_def_cfa_offset 8 + .cfi_rel_offset ebx, 0 + pushl %ecx + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset ecx, 0 + pushl %edx + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset edx, 0 + pushl %esi + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset esi, 0 + pushl %edi + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset edi, 0 + pushl %ebp + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset ebp, 0 + mov 28(%esp), %ebx + mov 32(%esp), %ecx + mov 36(%esp), %edx + mov 40(%esp), %esi + mov 44(%esp), %edi + mov 48(%esp), %ebp + movl $__NR_splice, %eax + int $0x80 + cmpl $-MAX_ERRNO, %eax + jb 1f + negl %eax + pushl %eax + call __set_errno + addl $4, %esp +1: + popl %ebp + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + ret +END(splice) diff --git a/libc/arch-x86/syscalls/tee.S b/libc/arch-x86/syscalls/tee.S new file mode 100644 index 000000000..9422660a8 --- /dev/null +++ b/libc/arch-x86/syscalls/tee.S @@ -0,0 +1,36 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +ENTRY(tee) + pushl %ebx + .cfi_def_cfa_offset 8 + .cfi_rel_offset ebx, 0 + pushl %ecx + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset ecx, 0 + pushl %edx + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset edx, 0 + pushl %esi + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset esi, 0 + mov 20(%esp), %ebx + mov 24(%esp), %ecx + mov 28(%esp), %edx + mov 32(%esp), %esi + movl $__NR_tee, %eax + int $0x80 + cmpl $-MAX_ERRNO, %eax + jb 1f + negl %eax + pushl %eax + call __set_errno + addl $4, %esp +1: + popl %esi + popl %edx + popl %ecx + popl %ebx + ret +END(tee) diff --git a/libc/arch-x86/syscalls/vmsplice.S b/libc/arch-x86/syscalls/vmsplice.S new file mode 100644 index 000000000..2afba6043 --- /dev/null +++ b/libc/arch-x86/syscalls/vmsplice.S @@ -0,0 +1,36 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +ENTRY(vmsplice) + pushl %ebx + .cfi_def_cfa_offset 8 + .cfi_rel_offset ebx, 0 + pushl %ecx + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset ecx, 0 + pushl %edx + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset edx, 0 + pushl %esi + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset esi, 0 + mov 20(%esp), %ebx + mov 24(%esp), %ecx + mov 28(%esp), %edx + mov 32(%esp), %esi + movl $__NR_vmsplice, %eax + int $0x80 + cmpl $-MAX_ERRNO, %eax + jb 1f + negl %eax + pushl %eax + call __set_errno + addl $4, %esp +1: + popl %esi + popl %edx + popl %ecx + popl %ebx + ret +END(vmsplice) diff --git a/libc/arch-x86_64/syscalls/splice.S b/libc/arch-x86_64/syscalls/splice.S new file mode 100644 index 000000000..3c245a554 --- /dev/null +++ b/libc/arch-x86_64/syscalls/splice.S @@ -0,0 +1,16 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +ENTRY(splice) + movq %rcx, %r10 + movl $__NR_splice, %eax + syscall + cmpq $-MAX_ERRNO, %rax + jb 1f + negl %eax + movl %eax, %edi + call __set_errno +1: + ret +END(splice) diff --git a/libc/arch-x86_64/syscalls/tee.S b/libc/arch-x86_64/syscalls/tee.S new file mode 100644 index 000000000..ad5698c9d --- /dev/null +++ b/libc/arch-x86_64/syscalls/tee.S @@ -0,0 +1,16 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +ENTRY(tee) + movq %rcx, %r10 + movl $__NR_tee, %eax + syscall + cmpq $-MAX_ERRNO, %rax + jb 1f + negl %eax + movl %eax, %edi + call __set_errno +1: + ret +END(tee) diff --git a/libc/arch-x86_64/syscalls/vmsplice.S b/libc/arch-x86_64/syscalls/vmsplice.S new file mode 100644 index 000000000..cc94cc601 --- /dev/null +++ b/libc/arch-x86_64/syscalls/vmsplice.S @@ -0,0 +1,16 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +ENTRY(vmsplice) + movq %rcx, %r10 + movl $__NR_vmsplice, %eax + syscall + cmpq $-MAX_ERRNO, %rax + jb 1f + negl %eax + movl %eax, %edi + call __set_errno +1: + ret +END(vmsplice) diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h index cd68154f7..4450bb65f 100644 --- a/libc/include/fcntl.h +++ b/libc/include/fcntl.h @@ -33,6 +33,7 @@ #include #include #include +#include #include /* this is not required, but makes client code much happier */ __BEGIN_DECLS @@ -51,9 +52,12 @@ struct flock64 { #define F_SETLKW64 F_SETLKW #endif -#ifndef O_ASYNC -#define O_ASYNC FASYNC -#endif +#define O_ASYNC FASYNC + +#define SPLICE_F_MOVE 1 +#define SPLICE_F_NONBLOCK 2 +#define SPLICE_F_MORE 4 +#define SPLICE_F_GIFT 8 #define SYNC_FILE_RANGE_WAIT_BEFORE 1 #define SYNC_FILE_RANGE_WRITE 2 @@ -70,7 +74,10 @@ extern int open(const char*, int, ...); extern int open64(const char*, int, ...); extern int posix_fallocate64(int, off64_t, off64_t); extern int posix_fallocate(int, off_t, off_t); +extern ssize_t splice(int, off64_t*, int, off64_t*, size_t, unsigned int); +extern ssize_t tee(int, int, size_t, unsigned int); extern int unlinkat(int, const char*, int); +extern ssize_t vmsplice(int, const struct iovec*, size_t, unsigned int); #if defined(__BIONIC_FORTIFY) diff --git a/tests/fcntl_test.cpp b/tests/fcntl_test.cpp index fb6b07ee3..5f2029569 100644 --- a/tests/fcntl_test.cpp +++ b/tests/fcntl_test.cpp @@ -132,3 +132,87 @@ TEST(fcntl, f_getlk64) { close(fd); } + +TEST(fcntl, splice) { + int pipe_fds[2]; + ASSERT_EQ(0, pipe(pipe_fds)); + + int in = open("/proc/cpuinfo", O_RDONLY); + ASSERT_NE(in, -1); + + TemporaryFile tf; + + ssize_t bytes_read = splice(in, 0, pipe_fds[1], NULL, 8*1024, SPLICE_F_MORE | SPLICE_F_MOVE); + ASSERT_NE(bytes_read, -1); + + ssize_t bytes_written = splice(pipe_fds[0], NULL, tf.fd, 0, bytes_read, SPLICE_F_MORE | SPLICE_F_MOVE); + ASSERT_EQ(bytes_read, bytes_written); + + close(pipe_fds[0]); + close(pipe_fds[1]); + close(in); +} + +TEST(fcntl, vmsplice) { + int pipe_fds[2]; + ASSERT_EQ(0, pipe(pipe_fds)); + + iovec v[2]; + v[0].iov_base = const_cast("hello "); + v[0].iov_len = 6; + v[1].iov_base = const_cast("world\n"); + v[1].iov_len = 6; + ssize_t bytes_written = vmsplice(pipe_fds[1], v, sizeof(v)/sizeof(iovec), 0); + ASSERT_EQ(v[0].iov_len + v[1].iov_len, static_cast(bytes_written)); + close(pipe_fds[1]); + + char buf[BUFSIZ]; + FILE* fp = fdopen(pipe_fds[0], "r"); + ASSERT_TRUE(fp != NULL); + ASSERT_TRUE(fgets(buf, sizeof(buf), fp) != NULL); + fclose(fp); + ASSERT_STREQ("hello world\n", buf); +} + +TEST(fcntl, tee) { + char expected[256]; + FILE* expected_fp = fopen("/proc/version", "r"); + ASSERT_TRUE(expected_fp != NULL); + ASSERT_TRUE(fgets(expected, sizeof(expected), expected_fp) != NULL); + fclose(expected_fp); + + int pipe1[2]; + ASSERT_EQ(0, pipe(pipe1)); + + int pipe2[2]; + ASSERT_EQ(0, pipe(pipe2)); + + int in = open("/proc/version", O_RDONLY); + ASSERT_NE(in, -1); + + // Write /proc/version into pipe1. + ssize_t bytes_read = splice(in, 0, pipe1[1], NULL, 8*1024, SPLICE_F_MORE | SPLICE_F_MOVE); + ASSERT_NE(bytes_read, -1); + close(pipe1[1]); + + // Tee /proc/version from pipe1 into pipe2. + ssize_t bytes_teed = tee(pipe1[0], pipe2[1], SIZE_MAX, 0); + ASSERT_EQ(bytes_read, bytes_teed); + close(pipe2[1]); + + // The out fds of both pipe1 and pipe2 should now contain /proc/version. + char buf1[BUFSIZ]; + FILE* fp1 = fdopen(pipe1[0], "r"); + ASSERT_TRUE(fp1 != NULL); + ASSERT_TRUE(fgets(buf1, sizeof(buf1), fp1) != NULL); + fclose(fp1); + + char buf2[BUFSIZ]; + FILE* fp2 = fdopen(pipe2[0], "r"); + ASSERT_TRUE(fp2 != NULL); + ASSERT_TRUE(fgets(buf2, sizeof(buf2), fp2) != NULL); + fclose(fp2); + + ASSERT_STREQ(expected, buf1); + ASSERT_STREQ(expected, buf2); +}