1 /* 2 * QEMU I/O channels null driver 3 * 4 * Copyright (c) 2022 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-null.h" 23 #include "io/channel-watch.h" 24 #include "qapi/error.h" 25 #include "trace.h" 26 #include "qemu/iov.h" 27 28 typedef struct QIOChannelNullSource QIOChannelNullSource; 29 struct QIOChannelNullSource { 30 GSource parent; 31 QIOChannel *ioc; 32 GIOCondition condition; 33 }; 34 35 36 QIOChannelNull * 37 qio_channel_null_new(void) 38 { 39 QIOChannelNull *ioc; 40 41 ioc = QIO_CHANNEL_NULL(object_new(TYPE_QIO_CHANNEL_NULL)); 42 43 trace_qio_channel_null_new(ioc); 44 45 return ioc; 46 } 47 48 49 static void 50 qio_channel_null_init(Object *obj) 51 { 52 QIOChannelNull *ioc = QIO_CHANNEL_NULL(obj); 53 ioc->closed = false; 54 } 55 56 57 static ssize_t 58 qio_channel_null_readv(QIOChannel *ioc, 59 const struct iovec *iov, 60 size_t niov, 61 int **fds G_GNUC_UNUSED, 62 size_t *nfds G_GNUC_UNUSED, 63 Error **errp) 64 { 65 QIOChannelNull *nioc = QIO_CHANNEL_NULL(ioc); 66 67 if (nioc->closed) { 68 error_setg_errno(errp, EINVAL, 69 "Channel is closed"); 70 return -1; 71 } 72 73 return 0; 74 } 75 76 77 static ssize_t 78 qio_channel_null_writev(QIOChannel *ioc, 79 const struct iovec *iov, 80 size_t niov, 81 int *fds G_GNUC_UNUSED, 82 size_t nfds G_GNUC_UNUSED, 83 int flags G_GNUC_UNUSED, 84 Error **errp) 85 { 86 QIOChannelNull *nioc = QIO_CHANNEL_NULL(ioc); 87 88 if (nioc->closed) { 89 error_setg_errno(errp, EINVAL, 90 "Channel is closed"); 91 return -1; 92 } 93 94 return iov_size(iov, niov); 95 } 96 97 98 static int 99 qio_channel_null_set_blocking(QIOChannel *ioc G_GNUC_UNUSED, 100 bool enabled G_GNUC_UNUSED, 101 Error **errp G_GNUC_UNUSED) 102 { 103 return 0; 104 } 105 106 107 static off_t 108 qio_channel_null_seek(QIOChannel *ioc G_GNUC_UNUSED, 109 off_t offset G_GNUC_UNUSED, 110 int whence G_GNUC_UNUSED, 111 Error **errp G_GNUC_UNUSED) 112 { 113 return 0; 114 } 115 116 117 static int 118 qio_channel_null_close(QIOChannel *ioc, 119 Error **errp G_GNUC_UNUSED) 120 { 121 QIOChannelNull *nioc = QIO_CHANNEL_NULL(ioc); 122 123 nioc->closed = true; 124 return 0; 125 } 126 127 128 static void 129 qio_channel_null_set_aio_fd_handler(QIOChannel *ioc G_GNUC_UNUSED, 130 AioContext *ctx G_GNUC_UNUSED, 131 IOHandler *io_read G_GNUC_UNUSED, 132 IOHandler *io_write G_GNUC_UNUSED, 133 void *opaque G_GNUC_UNUSED) 134 { 135 } 136 137 138 static gboolean 139 qio_channel_null_source_prepare(GSource *source G_GNUC_UNUSED, 140 gint *timeout) 141 { 142 *timeout = -1; 143 144 return TRUE; 145 } 146 147 148 static gboolean 149 qio_channel_null_source_check(GSource *source G_GNUC_UNUSED) 150 { 151 return TRUE; 152 } 153 154 155 static gboolean 156 qio_channel_null_source_dispatch(GSource *source, 157 GSourceFunc callback, 158 gpointer user_data) 159 { 160 QIOChannelFunc func = (QIOChannelFunc)callback; 161 QIOChannelNullSource *ssource = (QIOChannelNullSource *)source; 162 163 return (*func)(ssource->ioc, 164 ssource->condition, 165 user_data); 166 } 167 168 169 static void 170 qio_channel_null_source_finalize(GSource *source) 171 { 172 QIOChannelNullSource *ssource = (QIOChannelNullSource *)source; 173 174 object_unref(OBJECT(ssource->ioc)); 175 } 176 177 178 GSourceFuncs qio_channel_null_source_funcs = { 179 qio_channel_null_source_prepare, 180 qio_channel_null_source_check, 181 qio_channel_null_source_dispatch, 182 qio_channel_null_source_finalize 183 }; 184 185 186 static GSource * 187 qio_channel_null_create_watch(QIOChannel *ioc, 188 GIOCondition condition) 189 { 190 GSource *source; 191 QIOChannelNullSource *ssource; 192 193 source = g_source_new(&qio_channel_null_source_funcs, 194 sizeof(QIOChannelNullSource)); 195 ssource = (QIOChannelNullSource *)source; 196 197 ssource->ioc = ioc; 198 object_ref(OBJECT(ioc)); 199 200 ssource->condition = condition; 201 202 return source; 203 } 204 205 206 static void 207 qio_channel_null_class_init(ObjectClass *klass, 208 void *class_data G_GNUC_UNUSED) 209 { 210 QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); 211 212 ioc_klass->io_writev = qio_channel_null_writev; 213 ioc_klass->io_readv = qio_channel_null_readv; 214 ioc_klass->io_set_blocking = qio_channel_null_set_blocking; 215 ioc_klass->io_seek = qio_channel_null_seek; 216 ioc_klass->io_close = qio_channel_null_close; 217 ioc_klass->io_create_watch = qio_channel_null_create_watch; 218 ioc_klass->io_set_aio_fd_handler = qio_channel_null_set_aio_fd_handler; 219 } 220 221 222 static const TypeInfo qio_channel_null_info = { 223 .parent = TYPE_QIO_CHANNEL, 224 .name = TYPE_QIO_CHANNEL_NULL, 225 .instance_size = sizeof(QIOChannelNull), 226 .instance_init = qio_channel_null_init, 227 .class_init = qio_channel_null_class_init, 228 }; 229 230 231 static void 232 qio_channel_null_register_types(void) 233 { 234 type_register_static(&qio_channel_null_info); 235 } 236 237 type_init(qio_channel_null_register_types); 238