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 int flags, 64 Error **errp) 65 { 66 QIOChannelNull *nioc = QIO_CHANNEL_NULL(ioc); 67 68 if (nioc->closed) { 69 error_setg_errno(errp, EINVAL, 70 "Channel is closed"); 71 return -1; 72 } 73 74 return 0; 75 } 76 77 78 static ssize_t 79 qio_channel_null_writev(QIOChannel *ioc, 80 const struct iovec *iov, 81 size_t niov, 82 int *fds G_GNUC_UNUSED, 83 size_t nfds G_GNUC_UNUSED, 84 int flags G_GNUC_UNUSED, 85 Error **errp) 86 { 87 QIOChannelNull *nioc = QIO_CHANNEL_NULL(ioc); 88 89 if (nioc->closed) { 90 error_setg_errno(errp, EINVAL, 91 "Channel is closed"); 92 return -1; 93 } 94 95 return iov_size(iov, niov); 96 } 97 98 99 static int 100 qio_channel_null_set_blocking(QIOChannel *ioc G_GNUC_UNUSED, 101 bool enabled G_GNUC_UNUSED, 102 Error **errp G_GNUC_UNUSED) 103 { 104 return 0; 105 } 106 107 108 static off_t 109 qio_channel_null_seek(QIOChannel *ioc G_GNUC_UNUSED, 110 off_t offset G_GNUC_UNUSED, 111 int whence G_GNUC_UNUSED, 112 Error **errp G_GNUC_UNUSED) 113 { 114 return 0; 115 } 116 117 118 static int 119 qio_channel_null_close(QIOChannel *ioc, 120 Error **errp G_GNUC_UNUSED) 121 { 122 QIOChannelNull *nioc = QIO_CHANNEL_NULL(ioc); 123 124 nioc->closed = true; 125 return 0; 126 } 127 128 129 static void 130 qio_channel_null_set_aio_fd_handler(QIOChannel *ioc G_GNUC_UNUSED, 131 AioContext *read_ctx G_GNUC_UNUSED, 132 IOHandler *io_read G_GNUC_UNUSED, 133 AioContext *write_ctx G_GNUC_UNUSED, 134 IOHandler *io_write G_GNUC_UNUSED, 135 void *opaque G_GNUC_UNUSED) 136 { 137 } 138 139 140 static gboolean 141 qio_channel_null_source_prepare(GSource *source G_GNUC_UNUSED, 142 gint *timeout) 143 { 144 *timeout = -1; 145 146 return TRUE; 147 } 148 149 150 static gboolean 151 qio_channel_null_source_check(GSource *source G_GNUC_UNUSED) 152 { 153 return TRUE; 154 } 155 156 157 static gboolean 158 qio_channel_null_source_dispatch(GSource *source, 159 GSourceFunc callback, 160 gpointer user_data) 161 { 162 QIOChannelFunc func = (QIOChannelFunc)callback; 163 QIOChannelNullSource *ssource = (QIOChannelNullSource *)source; 164 165 return (*func)(ssource->ioc, 166 ssource->condition, 167 user_data); 168 } 169 170 171 static void 172 qio_channel_null_source_finalize(GSource *source) 173 { 174 QIOChannelNullSource *ssource = (QIOChannelNullSource *)source; 175 176 object_unref(OBJECT(ssource->ioc)); 177 } 178 179 180 GSourceFuncs qio_channel_null_source_funcs = { 181 qio_channel_null_source_prepare, 182 qio_channel_null_source_check, 183 qio_channel_null_source_dispatch, 184 qio_channel_null_source_finalize 185 }; 186 187 188 static GSource * 189 qio_channel_null_create_watch(QIOChannel *ioc, 190 GIOCondition condition) 191 { 192 GSource *source; 193 QIOChannelNullSource *ssource; 194 195 source = g_source_new(&qio_channel_null_source_funcs, 196 sizeof(QIOChannelNullSource)); 197 ssource = (QIOChannelNullSource *)source; 198 199 ssource->ioc = ioc; 200 object_ref(OBJECT(ioc)); 201 202 ssource->condition = condition; 203 204 return source; 205 } 206 207 208 static void 209 qio_channel_null_class_init(ObjectClass *klass, 210 void *class_data G_GNUC_UNUSED) 211 { 212 QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); 213 214 ioc_klass->io_writev = qio_channel_null_writev; 215 ioc_klass->io_readv = qio_channel_null_readv; 216 ioc_klass->io_set_blocking = qio_channel_null_set_blocking; 217 ioc_klass->io_seek = qio_channel_null_seek; 218 ioc_klass->io_close = qio_channel_null_close; 219 ioc_klass->io_create_watch = qio_channel_null_create_watch; 220 ioc_klass->io_set_aio_fd_handler = qio_channel_null_set_aio_fd_handler; 221 } 222 223 224 static const TypeInfo qio_channel_null_info = { 225 .parent = TYPE_QIO_CHANNEL, 226 .name = TYPE_QIO_CHANNEL_NULL, 227 .instance_size = sizeof(QIOChannelNull), 228 .instance_init = qio_channel_null_init, 229 .class_init = qio_channel_null_class_init, 230 }; 231 232 233 static void 234 qio_channel_null_register_types(void) 235 { 236 type_register_static(&qio_channel_null_info); 237 } 238 239 type_init(qio_channel_null_register_types); 240