char: move QIOChannel-related stuff to char-io.h
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
		
							parent
							
								
									09fbe4e3e1
								
							
						
					
					
						commit
						a6da7ffa38
					
				| @ -1,4 +1,5 @@ | ||||
| chardev-obj-y += char.o | ||||
| chardev-obj-y += char-io.o | ||||
| chardev-obj-y += char-mux.o | ||||
| chardev-obj-y += char-null.o | ||||
| chardev-obj-y += char-ringbuf.o | ||||
|  | ||||
							
								
								
									
										192
									
								
								chardev/char-io.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								chardev/char-io.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,192 @@ | ||||
| /*
 | ||||
|  * QEMU System Emulator | ||||
|  * | ||||
|  * Copyright (c) 2003-2008 Fabrice Bellard | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
| #include "qemu/osdep.h" | ||||
| #include "char-io.h" | ||||
| 
 | ||||
| typedef struct IOWatchPoll { | ||||
|     GSource parent; | ||||
| 
 | ||||
|     QIOChannel *ioc; | ||||
|     GSource *src; | ||||
| 
 | ||||
|     IOCanReadHandler *fd_can_read; | ||||
|     GSourceFunc fd_read; | ||||
|     void *opaque; | ||||
|     GMainContext *context; | ||||
| } IOWatchPoll; | ||||
| 
 | ||||
| static IOWatchPoll *io_watch_poll_from_source(GSource *source) | ||||
| { | ||||
|     return container_of(source, IOWatchPoll, parent); | ||||
| } | ||||
| 
 | ||||
| static gboolean io_watch_poll_prepare(GSource *source, | ||||
|                                       gint *timeout) | ||||
| { | ||||
|     IOWatchPoll *iwp = io_watch_poll_from_source(source); | ||||
|     bool now_active = iwp->fd_can_read(iwp->opaque) > 0; | ||||
|     bool was_active = iwp->src != NULL; | ||||
|     if (was_active == now_active) { | ||||
|         return FALSE; | ||||
|     } | ||||
| 
 | ||||
|     if (now_active) { | ||||
|         iwp->src = qio_channel_create_watch( | ||||
|             iwp->ioc, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL); | ||||
|         g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL); | ||||
|         g_source_attach(iwp->src, iwp->context); | ||||
|     } else { | ||||
|         g_source_destroy(iwp->src); | ||||
|         g_source_unref(iwp->src); | ||||
|         iwp->src = NULL; | ||||
|     } | ||||
|     return FALSE; | ||||
| } | ||||
| 
 | ||||
| static gboolean io_watch_poll_check(GSource *source) | ||||
| { | ||||
|     return FALSE; | ||||
| } | ||||
| 
 | ||||
| static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback, | ||||
|                                        gpointer user_data) | ||||
| { | ||||
|     abort(); | ||||
| } | ||||
| 
 | ||||
| static void io_watch_poll_finalize(GSource *source) | ||||
| { | ||||
|     /* Due to a glib bug, removing the last reference to a source
 | ||||
|      * inside a finalize callback causes recursive locking (and a | ||||
|      * deadlock).  This is not a problem inside other callbacks, | ||||
|      * including dispatch callbacks, so we call io_remove_watch_poll | ||||
|      * to remove this source.  At this point, iwp->src must | ||||
|      * be NULL, or we would leak it. | ||||
|      * | ||||
|      * This would be solved much more elegantly by child sources, | ||||
|      * but we support older glib versions that do not have them. | ||||
|      */ | ||||
|     IOWatchPoll *iwp = io_watch_poll_from_source(source); | ||||
|     assert(iwp->src == NULL); | ||||
| } | ||||
| 
 | ||||
| static GSourceFuncs io_watch_poll_funcs = { | ||||
|     .prepare = io_watch_poll_prepare, | ||||
|     .check = io_watch_poll_check, | ||||
|     .dispatch = io_watch_poll_dispatch, | ||||
|     .finalize = io_watch_poll_finalize, | ||||
| }; | ||||
| 
 | ||||
| guint io_add_watch_poll(Chardev *chr, | ||||
|                         QIOChannel *ioc, | ||||
|                         IOCanReadHandler *fd_can_read, | ||||
|                         QIOChannelFunc fd_read, | ||||
|                         gpointer user_data, | ||||
|                         GMainContext *context) | ||||
| { | ||||
|     IOWatchPoll *iwp; | ||||
|     int tag; | ||||
|     char *name; | ||||
| 
 | ||||
|     iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs, | ||||
|                                        sizeof(IOWatchPoll)); | ||||
|     iwp->fd_can_read = fd_can_read; | ||||
|     iwp->opaque = user_data; | ||||
|     iwp->ioc = ioc; | ||||
|     iwp->fd_read = (GSourceFunc) fd_read; | ||||
|     iwp->src = NULL; | ||||
|     iwp->context = context; | ||||
| 
 | ||||
|     name = g_strdup_printf("chardev-iowatch-%s", chr->label); | ||||
|     g_source_set_name((GSource *)iwp, name); | ||||
|     g_free(name); | ||||
| 
 | ||||
|     tag = g_source_attach(&iwp->parent, context); | ||||
|     g_source_unref(&iwp->parent); | ||||
|     return tag; | ||||
| } | ||||
| 
 | ||||
| static void io_remove_watch_poll(guint tag) | ||||
| { | ||||
|     GSource *source; | ||||
|     IOWatchPoll *iwp; | ||||
| 
 | ||||
|     g_return_if_fail(tag > 0); | ||||
| 
 | ||||
|     source = g_main_context_find_source_by_id(NULL, tag); | ||||
|     g_return_if_fail(source != NULL); | ||||
| 
 | ||||
|     iwp = io_watch_poll_from_source(source); | ||||
|     if (iwp->src) { | ||||
|         g_source_destroy(iwp->src); | ||||
|         g_source_unref(iwp->src); | ||||
|         iwp->src = NULL; | ||||
|     } | ||||
|     g_source_destroy(&iwp->parent); | ||||
| } | ||||
| 
 | ||||
| void remove_fd_in_watch(Chardev *chr) | ||||
| { | ||||
|     if (chr->fd_in_tag) { | ||||
|         io_remove_watch_poll(chr->fd_in_tag); | ||||
|         chr->fd_in_tag = 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| int io_channel_send_full(QIOChannel *ioc, | ||||
|                          const void *buf, size_t len, | ||||
|                          int *fds, size_t nfds) | ||||
| { | ||||
|     size_t offset = 0; | ||||
| 
 | ||||
|     while (offset < len) { | ||||
|         ssize_t ret = 0; | ||||
|         struct iovec iov = { .iov_base = (char *)buf + offset, | ||||
|                              .iov_len = len - offset }; | ||||
| 
 | ||||
|         ret = qio_channel_writev_full( | ||||
|             ioc, &iov, 1, | ||||
|             fds, nfds, NULL); | ||||
|         if (ret == QIO_CHANNEL_ERR_BLOCK) { | ||||
|             if (offset) { | ||||
|                 return offset; | ||||
|             } | ||||
| 
 | ||||
|             errno = EAGAIN; | ||||
|             return -1; | ||||
|         } else if (ret < 0) { | ||||
|             errno = EINVAL; | ||||
|             return -1; | ||||
|         } | ||||
| 
 | ||||
|         offset += ret; | ||||
|     } | ||||
| 
 | ||||
|     return offset; | ||||
| } | ||||
| 
 | ||||
| int io_channel_send(QIOChannel *ioc, const void *buf, size_t len) | ||||
| { | ||||
|     return io_channel_send_full(ioc, buf, len, NULL, 0); | ||||
| } | ||||
							
								
								
									
										46
									
								
								chardev/char-io.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								chardev/char-io.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| /*
 | ||||
|  * QEMU System Emulator | ||||
|  * | ||||
|  * Copyright (c) 2003-2008 Fabrice Bellard | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
| #ifndef CHAR_IO_H | ||||
| #define CHAR_IO_H | ||||
| 
 | ||||
| #include "qemu-common.h" | ||||
| #include "io/channel.h" | ||||
| #include "sysemu/char.h" | ||||
| 
 | ||||
| /* Can only be used for read */ | ||||
| guint io_add_watch_poll(Chardev *chr, | ||||
|                         QIOChannel *ioc, | ||||
|                         IOCanReadHandler *fd_can_read, | ||||
|                         QIOChannelFunc fd_read, | ||||
|                         gpointer user_data, | ||||
|                         GMainContext *context); | ||||
| 
 | ||||
| void remove_fd_in_watch(Chardev *chr); | ||||
| 
 | ||||
| int io_channel_send(QIOChannel *ioc, const void *buf, size_t len); | ||||
| 
 | ||||
| int io_channel_send_full(QIOChannel *ioc, const void *buf, size_t len, | ||||
|                          int *fds, size_t nfds); | ||||
| 
 | ||||
| #endif /* CHAR_IO_H */ | ||||
							
								
								
									
										174
									
								
								chardev/char.c
									
									
									
									
									
								
							
							
						
						
									
										174
									
								
								chardev/char.c
									
									
									
									
									
								
							| @ -86,6 +86,7 @@ | ||||
| #include "ui/qemu-spice.h" | ||||
| 
 | ||||
| #include "char-mux.h" | ||||
| #include "char-io.h" | ||||
| 
 | ||||
| #define TCP_MAX_FDS 16 | ||||
| 
 | ||||
| @ -479,8 +480,6 @@ void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...) | ||||
|     va_end(ap); | ||||
| } | ||||
| 
 | ||||
| static void remove_fd_in_watch(Chardev *chr); | ||||
| 
 | ||||
| static void qemu_char_open(Chardev *chr, ChardevBackend *backend, | ||||
|                            bool *be_opened, Error **errp) | ||||
| { | ||||
| @ -716,178 +715,7 @@ void qemu_chr_fe_take_focus(CharBackend *b) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| typedef struct IOWatchPoll | ||||
| { | ||||
|     GSource parent; | ||||
| 
 | ||||
|     QIOChannel *ioc; | ||||
|     GSource *src; | ||||
| 
 | ||||
|     IOCanReadHandler *fd_can_read; | ||||
|     GSourceFunc fd_read; | ||||
|     void *opaque; | ||||
|     GMainContext *context; | ||||
| } IOWatchPoll; | ||||
| 
 | ||||
| static IOWatchPoll *io_watch_poll_from_source(GSource *source) | ||||
| { | ||||
|     return container_of(source, IOWatchPoll, parent); | ||||
| } | ||||
| 
 | ||||
| static gboolean io_watch_poll_prepare(GSource *source, | ||||
|                                       gint *timeout_) | ||||
| { | ||||
|     IOWatchPoll *iwp = io_watch_poll_from_source(source); | ||||
|     bool now_active = iwp->fd_can_read(iwp->opaque) > 0; | ||||
|     bool was_active = iwp->src != NULL; | ||||
|     if (was_active == now_active) { | ||||
|         return FALSE; | ||||
|     } | ||||
| 
 | ||||
|     if (now_active) { | ||||
|         iwp->src = qio_channel_create_watch( | ||||
|             iwp->ioc, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL); | ||||
|         g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL); | ||||
|         g_source_attach(iwp->src, iwp->context); | ||||
|     } else { | ||||
|         g_source_destroy(iwp->src); | ||||
|         g_source_unref(iwp->src); | ||||
|         iwp->src = NULL; | ||||
|     } | ||||
|     return FALSE; | ||||
| } | ||||
| 
 | ||||
| static gboolean io_watch_poll_check(GSource *source) | ||||
| { | ||||
|     return FALSE; | ||||
| } | ||||
| 
 | ||||
| static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback, | ||||
|                                        gpointer user_data) | ||||
| { | ||||
|     abort(); | ||||
| } | ||||
| 
 | ||||
| static void io_watch_poll_finalize(GSource *source) | ||||
| { | ||||
|     /* Due to a glib bug, removing the last reference to a source
 | ||||
|      * inside a finalize callback causes recursive locking (and a | ||||
|      * deadlock).  This is not a problem inside other callbacks, | ||||
|      * including dispatch callbacks, so we call io_remove_watch_poll | ||||
|      * to remove this source.  At this point, iwp->src must | ||||
|      * be NULL, or we would leak it. | ||||
|      * | ||||
|      * This would be solved much more elegantly by child sources, | ||||
|      * but we support older glib versions that do not have them. | ||||
|      */ | ||||
|     IOWatchPoll *iwp = io_watch_poll_from_source(source); | ||||
|     assert(iwp->src == NULL); | ||||
| } | ||||
| 
 | ||||
| static GSourceFuncs io_watch_poll_funcs = { | ||||
|     .prepare = io_watch_poll_prepare, | ||||
|     .check = io_watch_poll_check, | ||||
|     .dispatch = io_watch_poll_dispatch, | ||||
|     .finalize = io_watch_poll_finalize, | ||||
| }; | ||||
| 
 | ||||
| /* Can only be used for read */ | ||||
| static guint io_add_watch_poll(Chardev *chr, | ||||
|                                QIOChannel *ioc, | ||||
|                                IOCanReadHandler *fd_can_read, | ||||
|                                QIOChannelFunc fd_read, | ||||
|                                gpointer user_data, | ||||
|                                GMainContext *context) | ||||
| { | ||||
|     IOWatchPoll *iwp; | ||||
|     int tag; | ||||
|     char *name; | ||||
| 
 | ||||
|     iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs, | ||||
|                                        sizeof(IOWatchPoll)); | ||||
|     iwp->fd_can_read = fd_can_read; | ||||
|     iwp->opaque = user_data; | ||||
|     iwp->ioc = ioc; | ||||
|     iwp->fd_read = (GSourceFunc) fd_read; | ||||
|     iwp->src = NULL; | ||||
|     iwp->context = context; | ||||
| 
 | ||||
|     name = g_strdup_printf("chardev-iowatch-%s", chr->label); | ||||
|     g_source_set_name((GSource *)iwp, name); | ||||
|     g_free(name); | ||||
| 
 | ||||
|     tag = g_source_attach(&iwp->parent, context); | ||||
|     g_source_unref(&iwp->parent); | ||||
|     return tag; | ||||
| } | ||||
| 
 | ||||
| static void io_remove_watch_poll(guint tag) | ||||
| { | ||||
|     GSource *source; | ||||
|     IOWatchPoll *iwp; | ||||
| 
 | ||||
|     g_return_if_fail (tag > 0); | ||||
| 
 | ||||
|     source = g_main_context_find_source_by_id(NULL, tag); | ||||
|     g_return_if_fail (source != NULL); | ||||
| 
 | ||||
|     iwp = io_watch_poll_from_source(source); | ||||
|     if (iwp->src) { | ||||
|         g_source_destroy(iwp->src); | ||||
|         g_source_unref(iwp->src); | ||||
|         iwp->src = NULL; | ||||
|     } | ||||
|     g_source_destroy(&iwp->parent); | ||||
| } | ||||
| 
 | ||||
| static void remove_fd_in_watch(Chardev *chr) | ||||
| { | ||||
|     if (chr->fd_in_tag) { | ||||
|         io_remove_watch_poll(chr->fd_in_tag); | ||||
|         chr->fd_in_tag = 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static int io_channel_send_full(QIOChannel *ioc, | ||||
|                                 const void *buf, size_t len, | ||||
|                                 int *fds, size_t nfds) | ||||
| { | ||||
|     size_t offset = 0; | ||||
| 
 | ||||
|     while (offset < len) { | ||||
|         ssize_t ret = 0; | ||||
|         struct iovec iov = { .iov_base = (char *)buf + offset, | ||||
|                              .iov_len = len - offset }; | ||||
| 
 | ||||
|         ret = qio_channel_writev_full( | ||||
|             ioc, &iov, 1, | ||||
|             fds, nfds, NULL); | ||||
|         if (ret == QIO_CHANNEL_ERR_BLOCK) { | ||||
|             if (offset) { | ||||
|                 return offset; | ||||
|             } | ||||
| 
 | ||||
|             errno = EAGAIN; | ||||
|             return -1; | ||||
|         } else if (ret < 0) { | ||||
|             errno = EINVAL; | ||||
|             return -1; | ||||
|         } | ||||
| 
 | ||||
|         offset += ret; | ||||
|     } | ||||
| 
 | ||||
|     return offset; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #ifndef _WIN32 | ||||
| static int io_channel_send(QIOChannel *ioc, const void *buf, size_t len) | ||||
| { | ||||
|     return io_channel_send_full(ioc, buf, len, NULL, 0); | ||||
| } | ||||
| 
 | ||||
| typedef struct FDChardev { | ||||
|     Chardev parent; | ||||
|     Chardev *chr; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Marc-André Lureau
						Marc-André Lureau