From: Jens Axboe Date: Fri, 21 Apr 2006 07:44:23 +0000 (+0200) Subject: [PATCH] Add vmsplice X-Git-Url: https://git.kernel.dk/?a=commitdiff_plain;h=7ee0f27f5bdfc8005e497efc8336606654280def;p=splice.git [PATCH] Add vmsplice --- diff --git a/.gitignore b/.gitignore index 5934fde..0b94c09 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ splice-net splice-out splice-test4c splice-test4s +vmsplice diff --git a/Makefile b/Makefile index 29d76a4..c9618c1 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc CFLAGS = -Wall -O2 -g -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -PROGS = ktee ktee-net splice-cp splice-in splice-out splice-net splice-test4c splice-test4s +PROGS = ktee ktee-net splice-cp splice-in splice-out splice-net splice-test4c splice-test4s vmsplice all: depend $(PROGS) diff --git a/splice.h b/splice.h index 0cdd1ca..e1a0592 100644 --- a/splice.h +++ b/splice.h @@ -4,19 +4,28 @@ #if defined(__i386__) #define __NR_splice 313 #define __NR_tee 315 +#define __NR_vmsplice 316 #elif defined(__x86_64__) #define __NR_splice 275 #define __NR_tee 276 +#define __NR_vmsplice 278 #elif defined(__powerpc__) || defined(__powerpc64__) #define __NR_splice 283 #define __NR_tee 284 +#define __NR_vmsplice 285 #elif defined(__ia64__) #define __NR_splice 1297 #define __NR_tee 1301 +#define __NR_vmsplice 1301 #else #error unsupported arch #endif +#ifndef F_SETPSZ +#define F_SETPSZ 15 +#define F_GETPSZ 16 +#endif + #define SPLICE_F_MOVE (0x01) /* move pages instead of copying */ #define SPLICE_F_NONBLOCK (0x02) /* don't block on the pipe splicing (but */ /* we may still block on the fd we splice */ @@ -35,6 +44,11 @@ static inline int tee(int fdin, int fdout, size_t len, unsigned int flags) return syscall(__NR_tee, fdin, fdout, len, flags); } +static inline int vmsplice(int fd, void *buffer, size_t len, unsigned int flags) +{ + return syscall(__NR_vmsplice, fd, buffer, len, flags); +} + #define SPLICE_SIZE (64*1024) #define BUG_ON(c) assert(!(c)) diff --git a/vmsplice.c b/vmsplice.c new file mode 100644 index 0000000..be77534 --- /dev/null +++ b/vmsplice.c @@ -0,0 +1,105 @@ +/* + * Use vmsplice to fill some user memory into a pipe. vmsplice writes + * to stdout, so that must be a pipe. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "splice.h" + +#define ALIGN_BUF + +#ifdef ALIGN_BUF +#define ALIGN_MASK (65535) /* 64k-1, should just be PAGE_SIZE - 1 */ +#define ALIGN(buf) (void *) (((unsigned long) (buf) + ALIGN_MASK) & ~ALIGN_MASK) +#else +#define ALIGN_MASK (0) +#define ALIGN(buf) (buf) +#endif + +int do_vmsplice(int fd, void *buffer, int len) +{ + struct pollfd pfd = { .fd = fd, .events = POLLOUT, }; + int written; + + while (len) { + /* + * in a real app you'd be more clever with poll of course, + * here we are basically just blocking on output room and + * not using the free time for anything interesting. + */ + if (poll(&pfd, 1, -1) < 0) + return error("poll"); + + written = vmsplice(fd, buffer, min(SPLICE_SIZE, len), 0); + + if (written <= 0) + return error("vmsplice"); + + len -= written; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + unsigned char *buffer; + struct stat sb; + long page_size; + int i, ret; + + if (fstat(STDOUT_FILENO, &sb) < 0) + return error("stat"); + if (!S_ISFIFO(sb.st_mode)) { + fprintf(stderr, "stdout must be a pipe\n"); + return 1; + } + + ret = fcntl(STDOUT_FILENO, F_GETPSZ); + if (ret < 0) + return error("F_GETPSZ"); + + page_size = sysconf(_SC_PAGESIZE); + if (page_size < 0) + return error("_SC_PAGESIZE"); + + fprintf(stderr, "Pipe size: %d pages / %ld bytes\n", ret, ret * page_size); + + buffer = ALIGN(malloc(2 * SPLICE_SIZE + ALIGN_MASK)); + for (i = 0; i < 2 * SPLICE_SIZE; i++) + buffer[i] = (i & 0xff); + + do { + /* + * vmsplice the first half of the buffer into the pipe + */ + if (do_vmsplice(STDOUT_FILENO, buffer, SPLICE_SIZE)) + break; + + /* + * first half is now in pipe, but we don't quite know when + * we can reuse it. + */ + + /* + * vmsplice second half + */ + if (do_vmsplice(STDOUT_FILENO, buffer + SPLICE_SIZE, SPLICE_SIZE)) + break; + + /* + * We still don't know when we can reuse the second half of + * the buffer, but we do now know that all parts of the first + * half have been consumed from the pipe - so we can reuse that. + */ + } while (0); + + return 0; +}