master
c 161 lines 4.14 KB
Raw
1 /*
2 * QEMU I/O channel test helpers
3 *
4 * Copyright (c) 2015 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include "qemu/osdep.h"
22 #include "io-channel-helpers.h"
23 #include "qapi/error.h"
24 #include "qemu/iov.h"
25
26 struct QIOChannelTest {
27 QIOChannel *src;
28 QIOChannel *dst;
29 size_t len;
30 size_t niov;
31 char *input;
32 struct iovec *inputv;
33 char *output;
34 struct iovec *outputv;
35 Error *writeerr;
36 Error *readerr;
37 };
38
39
40 /* This thread sends all data using iovecs */
41 static gpointer test_io_thread_writer(gpointer opaque)
42 {
43 QIOChannelTest *data = opaque;
44
45 qio_channel_writev_all(data->src,
46 data->inputv,
47 data->niov,
48 &data->writeerr);
49
50 return NULL;
51 }
52
53
54 /* This thread receives all data using iovecs */
55 static gpointer test_io_thread_reader(gpointer opaque)
56 {
57 QIOChannelTest *data = opaque;
58
59 qio_channel_readv_all(data->dst,
60 data->outputv,
61 data->niov,
62 &data->readerr);
63
64 return NULL;
65 }
66
67
68 QIOChannelTest *qio_channel_test_new(void)
69 {
70 QIOChannelTest *data = g_new0(QIOChannelTest, 1);
71 size_t i;
72 size_t offset;
73
74
75 /* We'll send 1 MB of data */
76 #define CHUNK_COUNT 250
77 #define CHUNK_LEN 4194
78
79 data->len = CHUNK_COUNT * CHUNK_LEN;
80 data->input = g_new0(char, data->len);
81 data->output = g_new0(gchar, data->len);
82
83 /* Fill input with a pattern */
84 for (i = 0; i < data->len; i += CHUNK_LEN) {
85 memset(data->input + i, (i / CHUNK_LEN), CHUNK_LEN);
86 }
87
88 /* We'll split the data across a bunch of IO vecs */
89 data->niov = CHUNK_COUNT;
90 data->inputv = g_new0(struct iovec, data->niov);
91 data->outputv = g_new0(struct iovec, data->niov);
92
93 for (i = 0, offset = 0; i < data->niov; i++, offset += CHUNK_LEN) {
94 data->inputv[i].iov_base = data->input + offset;
95 data->outputv[i].iov_base = data->output + offset;
96 data->inputv[i].iov_len = CHUNK_LEN;
97 data->outputv[i].iov_len = CHUNK_LEN;
98 }
99
100 return data;
101 }
102
103 void qio_channel_test_run_threads(QIOChannelTest *test,
104 bool blocking,
105 QIOChannel *src,
106 QIOChannel *dst)
107 {
108 GThread *reader, *writer;
109
110 test->src = src;
111 test->dst = dst;
112
113 qio_channel_set_blocking(test->dst, blocking, &error_abort);
114 qio_channel_set_blocking(test->src, blocking, &error_abort);
115
116 reader = g_thread_new("reader",
117 test_io_thread_reader,
118 test);
119 writer = g_thread_new("writer",
120 test_io_thread_writer,
121 test);
122
123 g_thread_join(reader);
124 g_thread_join(writer);
125
126 test->dst = test->src = NULL;
127 }
128
129
130 void qio_channel_test_run_writer(QIOChannelTest *test,
131 QIOChannel *src)
132 {
133 test->src = src;
134 test_io_thread_writer(test);
135 test->src = NULL;
136 }
137
138
139 void qio_channel_test_run_reader(QIOChannelTest *test,
140 QIOChannel *dst)
141 {
142 test->dst = dst;
143 test_io_thread_reader(test);
144 test->dst = NULL;
145 }
146
147
148 void qio_channel_test_validate(QIOChannelTest *test)
149 {
150 g_assert(test->readerr == NULL);
151 g_assert(test->writeerr == NULL);
152 g_assert_cmpint(memcmp(test->input,
153 test->output,
154 test->len), ==, 0);
155
156 g_free(test->inputv);
157 g_free(test->outputv);
158 g_free(test->input);
159 g_free(test->output);
160 g_free(test);
161 }