[PATCH] vmsplice: update to iov syscall
[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>
dbcd0883
JA
10#include <string.h>
11#include <getopt.h>
7ee0f27f
JA
12#include <sys/poll.h>
13#include <sys/stat.h>
14#include <sys/types.h>
15
16#include "splice.h"
17
18#define ALIGN_BUF
19
20#ifdef ALIGN_BUF
21#define ALIGN_MASK (65535) /* 64k-1, should just be PAGE_SIZE - 1 */
22#define ALIGN(buf) (void *) (((unsigned long) (buf) + ALIGN_MASK) & ~ALIGN_MASK)
23#else
24#define ALIGN_MASK (0)
25#define ALIGN(buf) (buf)
26#endif
27
dbcd0883
JA
28static int do_clear;
29
7ee0f27f
JA
30int do_vmsplice(int fd, void *buffer, int len)
31{
32 struct pollfd pfd = { .fd = fd, .events = POLLOUT, };
33 int written;
34
35 while (len) {
001a41ec
JA
36 struct iovec iov = {
37 .iov_base = buffer,
38 .iov_len = min(SPLICE_SIZE, len),
39 };
40
7ee0f27f
JA
41 /*
42 * in a real app you'd be more clever with poll of course,
43 * here we are basically just blocking on output room and
44 * not using the free time for anything interesting.
45 */
46 if (poll(&pfd, 1, -1) < 0)
47 return error("poll");
48
001a41ec 49 written = vmsplice(fd, &iov, 1, 0);
7ee0f27f
JA
50
51 if (written <= 0)
52 return error("vmsplice");
53
54 len -= written;
ee0531f5 55 buffer += written;
7ee0f27f
JA
56 }
57
58 return 0;
59}
60
dbcd0883
JA
61static int usage(char *name)
62{
63 fprintf(stderr, "%s: [-c]\n", name);
64 return 1;
65}
66
67static int parse_options(int argc, char *argv[])
68{
69 int c, index = 1;
70
9cd0e3d8 71 while ((c = getopt(argc, argv, "c")) != -1) {
dbcd0883
JA
72 switch (c) {
73 case 'c':
74 do_clear = 1;
75 index++;
76 break;
77 default:
78 return -1;
79 }
80 }
81
82 return index;
83}
84
7ee0f27f
JA
85int main(int argc, char *argv[])
86{
87 unsigned char *buffer;
88 struct stat sb;
89 long page_size;
90 int i, ret;
91
dbcd0883
JA
92 if (parse_options(argc, argv) < 0)
93 return usage(argv[0]);
94
7ee0f27f
JA
95 if (fstat(STDOUT_FILENO, &sb) < 0)
96 return error("stat");
97 if (!S_ISFIFO(sb.st_mode)) {
98 fprintf(stderr, "stdout must be a pipe\n");
99 return 1;
100 }
101
102 ret = fcntl(STDOUT_FILENO, F_GETPSZ);
103 if (ret < 0)
104 return error("F_GETPSZ");
105
106 page_size = sysconf(_SC_PAGESIZE);
107 if (page_size < 0)
108 return error("_SC_PAGESIZE");
109
110 fprintf(stderr, "Pipe size: %d pages / %ld bytes\n", ret, ret * page_size);
111
112 buffer = ALIGN(malloc(2 * SPLICE_SIZE + ALIGN_MASK));
113 for (i = 0; i < 2 * SPLICE_SIZE; i++)
114 buffer[i] = (i & 0xff);
115
116 do {
117 /*
118 * vmsplice the first half of the buffer into the pipe
119 */
120 if (do_vmsplice(STDOUT_FILENO, buffer, SPLICE_SIZE))
121 break;
122
123 /*
124 * first half is now in pipe, but we don't quite know when
125 * we can reuse it.
126 */
127
128 /*
129 * vmsplice second half
130 */
131 if (do_vmsplice(STDOUT_FILENO, buffer + SPLICE_SIZE, SPLICE_SIZE))
132 break;
133
134 /*
135 * We still don't know when we can reuse the second half of
136 * the buffer, but we do now know that all parts of the first
137 * half have been consumed from the pipe - so we can reuse that.
138 */
dbcd0883
JA
139
140 /*
141 * Test option - clear the first half of the buffer, should
142 * be safe now
143 */
144 if (do_clear)
145 memset(buffer, 0x00, SPLICE_SIZE);
146
7ee0f27f
JA
147 } while (0);
148
149 return 0;
150}