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 } 162