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