1 /* 2 * QEMU System Emulator - managing I/O handler 3 * 4 * Copyright (c) 2003-2008 Fabrice Bellard 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25 #include "config-host.h" 26 #include "qemu-common.h" 27 #include "qemu-char.h" 28 #include "qemu-queue.h" 29 30 #ifndef _WIN32 31 #include <sys/wait.h> 32 #endif 33 34 typedef struct IOHandlerRecord { 35 int fd; 36 IOCanReadHandler *fd_read_poll; 37 IOHandler *fd_read; 38 IOHandler *fd_write; 39 int deleted; 40 void *opaque; 41 QLIST_ENTRY(IOHandlerRecord) next; 42 } IOHandlerRecord; 43 44 static QLIST_HEAD(, IOHandlerRecord) io_handlers = 45 QLIST_HEAD_INITIALIZER(io_handlers); 46 47 48 /* XXX: fd_read_poll should be suppressed, but an API change is 49 necessary in the character devices to suppress fd_can_read(). */ 50 int qemu_set_fd_handler2(int fd, 51 IOCanReadHandler *fd_read_poll, 52 IOHandler *fd_read, 53 IOHandler *fd_write, 54 void *opaque) 55 { 56 IOHandlerRecord *ioh; 57 58 if (!fd_read && !fd_write) { 59 QLIST_FOREACH(ioh, &io_handlers, next) { 60 if (ioh->fd == fd) { 61 ioh->deleted = 1; 62 break; 63 } 64 } 65 } else { 66 QLIST_FOREACH(ioh, &io_handlers, next) { 67 if (ioh->fd == fd) 68 goto found; 69 } 70 ioh = qemu_mallocz(sizeof(IOHandlerRecord)); 71 QLIST_INSERT_HEAD(&io_handlers, ioh, next); 72 found: 73 ioh->fd = fd; 74 ioh->fd_read_poll = fd_read_poll; 75 ioh->fd_read = fd_read; 76 ioh->fd_write = fd_write; 77 ioh->opaque = opaque; 78 ioh->deleted = 0; 79 } 80 return 0; 81 } 82 83 int qemu_set_fd_handler(int fd, 84 IOHandler *fd_read, 85 IOHandler *fd_write, 86 void *opaque) 87 { 88 return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque); 89 } 90 91 void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds) 92 { 93 IOHandlerRecord *ioh; 94 95 QLIST_FOREACH(ioh, &io_handlers, next) { 96 if (ioh->deleted) 97 continue; 98 if (ioh->fd_read && 99 (!ioh->fd_read_poll || 100 ioh->fd_read_poll(ioh->opaque) != 0)) { 101 FD_SET(ioh->fd, readfds); 102 if (ioh->fd > *pnfds) 103 *pnfds = ioh->fd; 104 } 105 if (ioh->fd_write) { 106 FD_SET(ioh->fd, writefds); 107 if (ioh->fd > *pnfds) 108 *pnfds = ioh->fd; 109 } 110 } 111 } 112 113 void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int ret) 114 { 115 if (ret > 0) { 116 IOHandlerRecord *pioh, *ioh; 117 118 QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) { 119 if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, readfds)) { 120 ioh->fd_read(ioh->opaque); 121 } 122 if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, writefds)) { 123 ioh->fd_write(ioh->opaque); 124 } 125 126 /* Do this last in case read/write handlers marked it for deletion */ 127 if (ioh->deleted) { 128 QLIST_REMOVE(ioh, next); 129 qemu_free(ioh); 130 } 131 } 132 } 133 } 134 135 /* reaping of zombies. right now we're not passing the status to 136 anyone, but it would be possible to add a callback. */ 137 #ifndef _WIN32 138 typedef struct ChildProcessRecord { 139 int pid; 140 QLIST_ENTRY(ChildProcessRecord) next; 141 } ChildProcessRecord; 142 143 static QLIST_HEAD(, ChildProcessRecord) child_watches = 144 QLIST_HEAD_INITIALIZER(child_watches); 145 146 static QEMUBH *sigchld_bh; 147 148 static void sigchld_handler(int signal) 149 { 150 qemu_bh_schedule(sigchld_bh); 151 } 152 153 static void sigchld_bh_handler(void *opaque) 154 { 155 ChildProcessRecord *rec, *next; 156 157 QLIST_FOREACH_SAFE(rec, &child_watches, next, next) { 158 if (waitpid(rec->pid, NULL, WNOHANG) == rec->pid) { 159 QLIST_REMOVE(rec, next); 160 qemu_free(rec); 161 } 162 } 163 } 164 165 static void qemu_init_child_watch(void) 166 { 167 struct sigaction act; 168 sigchld_bh = qemu_bh_new(sigchld_bh_handler, NULL); 169 170 act.sa_handler = sigchld_handler; 171 act.sa_flags = SA_NOCLDSTOP; 172 sigaction(SIGCHLD, &act, NULL); 173 } 174 175 int qemu_add_child_watch(pid_t pid) 176 { 177 ChildProcessRecord *rec; 178 179 if (!sigchld_bh) { 180 qemu_init_child_watch(); 181 } 182 183 QLIST_FOREACH(rec, &child_watches, next) { 184 if (rec->pid == pid) { 185 return 1; 186 } 187 } 188 rec = qemu_mallocz(sizeof(ChildProcessRecord)); 189 rec->pid = pid; 190 QLIST_INSERT_HEAD(&child_watches, rec, next); 191 return 0; 192 } 193 #endif 194