aboutsummaryrefslogtreecommitdiffstats
path: root/iohandler.c
diff options
context:
space:
mode:
authorfishsoupisgood <github@madingley.org>2019-04-29 01:17:54 +0100
committerfishsoupisgood <github@madingley.org>2019-05-27 03:43:43 +0100
commit3f2546b2ef55b661fd8dd69682b38992225e86f6 (patch)
tree65ca85f13617aee1dce474596800950f266a456c /iohandler.c
downloadqemu-3f2546b2ef55b661fd8dd69682b38992225e86f6.tar.gz
qemu-3f2546b2ef55b661fd8dd69682b38992225e86f6.tar.bz2
qemu-3f2546b2ef55b661fd8dd69682b38992225e86f6.zip
Initial import of qemu-2.4.1HEADmaster
Diffstat (limited to 'iohandler.c')
-rw-r--r--iohandler.c201
1 files changed, 201 insertions, 0 deletions
diff --git a/iohandler.c b/iohandler.c
new file mode 100644
index 00000000..826f713e
--- /dev/null
+++ b/iohandler.c
@@ -0,0 +1,201 @@
+/*
+ * QEMU System Emulator - managing I/O handler
+ *
+ * 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 "config-host.h"
+#include "qemu-common.h"
+#include "qemu/queue.h"
+#include "block/aio.h"
+#include "qemu/main-loop.h"
+
+#ifndef _WIN32
+#include <sys/wait.h>
+#endif
+
+typedef struct IOHandlerRecord {
+ IOHandler *fd_read;
+ IOHandler *fd_write;
+ void *opaque;
+ QLIST_ENTRY(IOHandlerRecord) next;
+ int fd;
+ int pollfds_idx;
+ bool deleted;
+} IOHandlerRecord;
+
+static QLIST_HEAD(, IOHandlerRecord) io_handlers =
+ QLIST_HEAD_INITIALIZER(io_handlers);
+
+void qemu_set_fd_handler(int fd,
+ IOHandler *fd_read,
+ IOHandler *fd_write,
+ void *opaque)
+{
+ IOHandlerRecord *ioh;
+
+ assert(fd >= 0);
+
+ if (!fd_read && !fd_write) {
+ QLIST_FOREACH(ioh, &io_handlers, next) {
+ if (ioh->fd == fd) {
+ ioh->deleted = 1;
+ break;
+ }
+ }
+ } else {
+ QLIST_FOREACH(ioh, &io_handlers, next) {
+ if (ioh->fd == fd)
+ goto found;
+ }
+ ioh = g_malloc0(sizeof(IOHandlerRecord));
+ QLIST_INSERT_HEAD(&io_handlers, ioh, next);
+ found:
+ ioh->fd = fd;
+ ioh->fd_read = fd_read;
+ ioh->fd_write = fd_write;
+ ioh->opaque = opaque;
+ ioh->pollfds_idx = -1;
+ ioh->deleted = 0;
+ qemu_notify_event();
+ }
+}
+
+void qemu_iohandler_fill(GArray *pollfds)
+{
+ IOHandlerRecord *ioh;
+
+ QLIST_FOREACH(ioh, &io_handlers, next) {
+ int events = 0;
+
+ if (ioh->deleted)
+ continue;
+ if (ioh->fd_read) {
+ events |= G_IO_IN | G_IO_HUP | G_IO_ERR;
+ }
+ if (ioh->fd_write) {
+ events |= G_IO_OUT | G_IO_ERR;
+ }
+ if (events) {
+ GPollFD pfd = {
+ .fd = ioh->fd,
+ .events = events,
+ };
+ ioh->pollfds_idx = pollfds->len;
+ g_array_append_val(pollfds, pfd);
+ } else {
+ ioh->pollfds_idx = -1;
+ }
+ }
+}
+
+void qemu_iohandler_poll(GArray *pollfds, int ret)
+{
+ if (ret > 0) {
+ IOHandlerRecord *pioh, *ioh;
+
+ QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
+ int revents = 0;
+
+ if (!ioh->deleted && ioh->pollfds_idx != -1) {
+ GPollFD *pfd = &g_array_index(pollfds, GPollFD,
+ ioh->pollfds_idx);
+ revents = pfd->revents;
+ }
+
+ if (!ioh->deleted && ioh->fd_read &&
+ (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
+ ioh->fd_read(ioh->opaque);
+ }
+ if (!ioh->deleted && ioh->fd_write &&
+ (revents & (G_IO_OUT | G_IO_ERR))) {
+ ioh->fd_write(ioh->opaque);
+ }
+
+ /* Do this last in case read/write handlers marked it for deletion */
+ if (ioh->deleted) {
+ QLIST_REMOVE(ioh, next);
+ g_free(ioh);
+ }
+ }
+ }
+}
+
+/* reaping of zombies. right now we're not passing the status to
+ anyone, but it would be possible to add a callback. */
+#ifndef _WIN32
+typedef struct ChildProcessRecord {
+ int pid;
+ QLIST_ENTRY(ChildProcessRecord) next;
+} ChildProcessRecord;
+
+static QLIST_HEAD(, ChildProcessRecord) child_watches =
+ QLIST_HEAD_INITIALIZER(child_watches);
+
+static QEMUBH *sigchld_bh;
+
+static void sigchld_handler(int signal)
+{
+ qemu_bh_schedule(sigchld_bh);
+}
+
+static void sigchld_bh_handler(void *opaque)
+{
+ ChildProcessRecord *rec, *next;
+
+ QLIST_FOREACH_SAFE(rec, &child_watches, next, next) {
+ if (waitpid(rec->pid, NULL, WNOHANG) == rec->pid) {
+ QLIST_REMOVE(rec, next);
+ g_free(rec);
+ }
+ }
+}
+
+static void qemu_init_child_watch(void)
+{
+ struct sigaction act;
+ sigchld_bh = qemu_bh_new(sigchld_bh_handler, NULL);
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = sigchld_handler;
+ act.sa_flags = SA_NOCLDSTOP;
+ sigaction(SIGCHLD, &act, NULL);
+}
+
+int qemu_add_child_watch(pid_t pid)
+{
+ ChildProcessRecord *rec;
+
+ if (!sigchld_bh) {
+ qemu_init_child_watch();
+ }
+
+ QLIST_FOREACH(rec, &child_watches, next) {
+ if (rec->pid == pid) {
+ return 1;
+ }
+ }
+ rec = g_malloc0(sizeof(ChildProcessRecord));
+ rec->pid = pid;
+ QLIST_INSERT_HEAD(&child_watches, rec, next);
+ return 0;
+}
+#endif