Commit | Line | Data |
---|---|---|
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> | |
0a6ff83b | 11 | #include <fcntl.h> |
7ee0f27f | 12 | #include <sys/poll.h> |
7ee0f27f JA |
13 | #include <sys/types.h> |
14 | ||
15 | #include "splice.h" | |
16 | ||
88a9ff87 | 17 | #define ALIGN(buf) (void *) (((unsigned long) (buf) + align_mask) & ~align_mask) |
7ee0f27f | 18 | |
dbcd0883 | 19 | static int do_clear; |
88a9ff87 | 20 | static int align_mask = 65535; |
96897528 JA |
21 | static int force_unalign; |
22 | static int splice_flags; | |
dbcd0883 | 23 | |
88a9ff87 | 24 | int do_vmsplice(int fd, void *b1, void *b2, int len) |
7ee0f27f JA |
25 | { |
26 | struct pollfd pfd = { .fd = fd, .events = POLLOUT, }; | |
88a9ff87 JA |
27 | struct iovec iov[] = { |
28 | { | |
29 | .iov_base = b1, | |
30 | .iov_len = len / 2, | |
31 | }, | |
32 | { | |
33 | .iov_base = b2, | |
34 | .iov_len = len / 2, | |
35 | }, | |
36 | }; | |
37 | int written, idx = 0; | |
7ee0f27f JA |
38 | |
39 | while (len) { | |
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 | ||
13b72067 | 48 | written = svmsplice(fd, &iov[idx], 2 - idx, splice_flags); |
7ee0f27f JA |
49 | |
50 | if (written <= 0) | |
51 | return error("vmsplice"); | |
52 | ||
53 | len -= written; | |
000b72a8 | 54 | if ((size_t) written >= iov[idx].iov_len) { |
88a9ff87 JA |
55 | int extra = written - iov[idx].iov_len; |
56 | ||
57 | idx++; | |
58 | iov[idx].iov_len -= extra; | |
59 | iov[idx].iov_base += extra; | |
60 | } else { | |
61 | iov[idx].iov_len -= written; | |
62 | iov[idx].iov_base += written; | |
63 | } | |
7ee0f27f JA |
64 | } |
65 | ||
66 | return 0; | |
67 | } | |
68 | ||
dbcd0883 JA |
69 | static int usage(char *name) |
70 | { | |
96897528 | 71 | fprintf(stderr, "%s: [-c(lear)] [-u(nalign)] [-g(ift)]| ...\n", name); |
dbcd0883 JA |
72 | return 1; |
73 | } | |
74 | ||
75 | static int parse_options(int argc, char *argv[]) | |
76 | { | |
77 | int c, index = 1; | |
78 | ||
96897528 | 79 | while ((c = getopt(argc, argv, "cug")) != -1) { |
dbcd0883 JA |
80 | switch (c) { |
81 | case 'c': | |
82 | do_clear = 1; | |
83 | index++; | |
84 | break; | |
88a9ff87 | 85 | case 'u': |
96897528 JA |
86 | force_unalign = 1; |
87 | index++; | |
88 | break; | |
89 | case 'g': | |
90 | splice_flags = SPLICE_F_GIFT; | |
88a9ff87 JA |
91 | index++; |
92 | break; | |
dbcd0883 JA |
93 | default: |
94 | return -1; | |
95 | } | |
96 | } | |
97 | ||
98 | return index; | |
99 | } | |
100 | ||
7ee0f27f JA |
101 | int main(int argc, char *argv[]) |
102 | { | |
88a9ff87 | 103 | unsigned char *b1, *b2; |
7ee0f27f | 104 | |
dbcd0883 JA |
105 | if (parse_options(argc, argv) < 0) |
106 | return usage(argv[0]); | |
107 | ||
76797253 | 108 | if (check_output_pipe()) |
f91353a3 | 109 | return usage(argv[0]); |
7ee0f27f | 110 | |
88a9ff87 JA |
111 | b1 = ALIGN(malloc(SPLICE_SIZE + align_mask)); |
112 | b2 = ALIGN(malloc(SPLICE_SIZE + align_mask)); | |
113 | ||
96897528 JA |
114 | if (force_unalign) { |
115 | b1 += 1024; | |
116 | b2 += 1024; | |
117 | } | |
118 | ||
88a9ff87 JA |
119 | memset(b1, 0xaa, SPLICE_SIZE); |
120 | memset(b2, 0xbb, SPLICE_SIZE); | |
7ee0f27f JA |
121 | |
122 | do { | |
88a9ff87 JA |
123 | int half = SPLICE_SIZE / 2; |
124 | ||
7ee0f27f JA |
125 | /* |
126 | * vmsplice the first half of the buffer into the pipe | |
127 | */ | |
88a9ff87 | 128 | if (do_vmsplice(STDOUT_FILENO, b1, b2, SPLICE_SIZE)) |
7ee0f27f JA |
129 | break; |
130 | ||
131 | /* | |
132 | * first half is now in pipe, but we don't quite know when | |
133 | * we can reuse it. | |
134 | */ | |
135 | ||
136 | /* | |
137 | * vmsplice second half | |
138 | */ | |
88a9ff87 | 139 | if (do_vmsplice(STDOUT_FILENO, b1 + half, b2 + half, SPLICE_SIZE)) |
7ee0f27f JA |
140 | break; |
141 | ||
142 | /* | |
143 | * We still don't know when we can reuse the second half of | |
144 | * the buffer, but we do now know that all parts of the first | |
145 | * half have been consumed from the pipe - so we can reuse that. | |
146 | */ | |
dbcd0883 JA |
147 | |
148 | /* | |
149 | * Test option - clear the first half of the buffer, should | |
150 | * be safe now | |
151 | */ | |
88a9ff87 JA |
152 | if (do_clear) { |
153 | memset(b1, 0x00, SPLICE_SIZE); | |
154 | memset(b2, 0x00, SPLICE_SIZE); | |
155 | } | |
7ee0f27f JA |
156 | } while (0); |
157 | ||
158 | return 0; | |
159 | } |