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