[PATCH] vmsplice: remember to update 'buffer' for multiple iterations
[splice.git] / vmsplice.c
CommitLineData
7ee0f27f
JA
1/*
2 * Use vmsplice to fill some user memory into a pipe. vmsplice writes
3 * to stdout, so that must be a pipe.
4 */
5#include <stdio.h>
6#include <stdlib.h>
7#include <unistd.h>
8#include <fcntl.h>
9#include <limits.h>
10#include <sys/poll.h>
11#include <sys/stat.h>
12#include <sys/types.h>
13
14#include "splice.h"
15
16#define ALIGN_BUF
17
18#ifdef ALIGN_BUF
19#define ALIGN_MASK (65535) /* 64k-1, should just be PAGE_SIZE - 1 */
20#define ALIGN(buf) (void *) (((unsigned long) (buf) + ALIGN_MASK) & ~ALIGN_MASK)
21#else
22#define ALIGN_MASK (0)
23#define ALIGN(buf) (buf)
24#endif
25
26int do_vmsplice(int fd, void *buffer, int len)
27{
28 struct pollfd pfd = { .fd = fd, .events = POLLOUT, };
29 int written;
30
31 while (len) {
32 /*
33 * in a real app you'd be more clever with poll of course,
34 * here we are basically just blocking on output room and
35 * not using the free time for anything interesting.
36 */
37 if (poll(&pfd, 1, -1) < 0)
38 return error("poll");
39
40 written = vmsplice(fd, buffer, min(SPLICE_SIZE, len), 0);
41
42 if (written <= 0)
43 return error("vmsplice");
44
45 len -= written;
ee0531f5 46 buffer += written;
7ee0f27f
JA
47 }
48
49 return 0;
50}
51
52int main(int argc, char *argv[])
53{
54 unsigned char *buffer;
55 struct stat sb;
56 long page_size;
57 int i, ret;
58
59 if (fstat(STDOUT_FILENO, &sb) < 0)
60 return error("stat");
61 if (!S_ISFIFO(sb.st_mode)) {
62 fprintf(stderr, "stdout must be a pipe\n");
63 return 1;
64 }
65
66 ret = fcntl(STDOUT_FILENO, F_GETPSZ);
67 if (ret < 0)
68 return error("F_GETPSZ");
69
70 page_size = sysconf(_SC_PAGESIZE);
71 if (page_size < 0)
72 return error("_SC_PAGESIZE");
73
74 fprintf(stderr, "Pipe size: %d pages / %ld bytes\n", ret, ret * page_size);
75
76 buffer = ALIGN(malloc(2 * SPLICE_SIZE + ALIGN_MASK));
77 for (i = 0; i < 2 * SPLICE_SIZE; i++)
78 buffer[i] = (i & 0xff);
79
80 do {
81 /*
82 * vmsplice the first half of the buffer into the pipe
83 */
84 if (do_vmsplice(STDOUT_FILENO, buffer, SPLICE_SIZE))
85 break;
86
87 /*
88 * first half is now in pipe, but we don't quite know when
89 * we can reuse it.
90 */
91
92 /*
93 * vmsplice second half
94 */
95 if (do_vmsplice(STDOUT_FILENO, buffer + SPLICE_SIZE, SPLICE_SIZE))
96 break;
97
98 /*
99 * We still don't know when we can reuse the second half of
100 * the buffer, but we do now know that all parts of the first
101 * half have been consumed from the pipe - so we can reuse that.
102 */
103 } while (0);
104
105 return 0;
106}