[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 1/2] iohandler: Convert I/O handler to GSource
From: |
Fam Zheng |
Subject: |
[Qemu-devel] [PATCH 1/2] iohandler: Convert I/O handler to GSource |
Date: |
Fri, 26 Sep 2014 01:21:48 +0800 |
Previously, I/O handler fd's are hooked into main loop by:
1) qemu_iohandler_fill to add the list of io handler fds to g_poll.
2) qemu_iohandler_poll to check the revent values and do the dispatch.
This patch moves all the fds into a GSource, which is attached to the
main event loop. This way we don't have to rebuild the whole list of fds
for every iteration, and there is a cleaner interface between us and
main loop. Furthermore, it makes adding a Linux specific implementation
(epoll) a lot easier.
Signed-off-by: Fam Zheng <address@hidden>
---
Makefile.objs | 2 +-
include/qemu/iohandler.h | 52 ++++++++++++++++
include/qemu/main-loop.h | 2 -
iohandler-posix.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++
iohandler.c | 90 +++-------------------------
main-loop.c | 6 +-
6 files changed, 215 insertions(+), 87 deletions(-)
create mode 100644 include/qemu/iohandler.h
create mode 100644 iohandler-posix.c
diff --git a/Makefile.objs b/Makefile.objs
index 97db978..55dbc36 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -8,7 +8,7 @@ util-obj-y = util/ qobject/ qapi/ qapi-types.o qapi-visit.o
qapi-event.o
block-obj-y = async.o thread-pool.o
block-obj-y += nbd.o block.o blockjob.o
-block-obj-y += main-loop.o iohandler.o qemu-timer.o
+block-obj-y += main-loop.o iohandler.o qemu-timer.o iohandler-posix.o
block-obj-$(CONFIG_POSIX) += aio-posix.o
block-obj-$(CONFIG_WIN32) += aio-win32.o
block-obj-y += block/
diff --git a/include/qemu/iohandler.h b/include/qemu/iohandler.h
new file mode 100644
index 0000000..e2af47d
--- /dev/null
+++ b/include/qemu/iohandler.h
@@ -0,0 +1,52 @@
+/*
+ * QEMU I/O Handler
+ *
+ * Copyright (c) 2014 Red Hat, Inc.
+ *
+ * Author: Fam Zheng <address@hidden>
+ *
+ * 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 QEMU_IOHANDLER_H
+#define QEMU_IOHANDLER_H
+
+#include "qemu/main-loop.h"
+
+typedef struct IOHandlerRecord {
+ IOCanReadHandler *fd_read_poll;
+ IOHandler *fd_read;
+ IOHandler *fd_write;
+ void *opaque;
+ QLIST_ENTRY(IOHandlerRecord) next;
+ int fd;
+ bool deleted;
+ GPollFD gpfd;
+ bool attached;
+} IOHandlerRecord;
+
+typedef struct {
+ GSource source;
+
+ QLIST_HEAD(, IOHandlerRecord) io_handlers;
+} IOHandlerSource;
+
+GSource *qemu_iohandler_get_source(void);
+
+#endif
diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
index 62c68c0..065944c 100644
--- a/include/qemu/main-loop.h
+++ b/include/qemu/main-loop.h
@@ -302,8 +302,6 @@ void qemu_mutex_unlock_iothread(void);
/* internal interfaces */
void qemu_fd_register(int fd);
-void qemu_iohandler_fill(GArray *pollfds);
-void qemu_iohandler_poll(GArray *pollfds, int rc);
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
void qemu_bh_schedule_idle(QEMUBH *bh);
diff --git a/iohandler-posix.c b/iohandler-posix.c
new file mode 100644
index 0000000..0fac91f
--- /dev/null
+++ b/iohandler-posix.c
@@ -0,0 +1,150 @@
+/*
+ * I/O Handler posix implementation
+ *
+ * Copyright (c) 2014 Red Hat, Inc.
+ *
+ * Author: Fam Zheng <address@hidden>
+ *
+ * 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/iohandler.h"
+
+/* Prepare for the poll by synchronize IO handler list to GSource. */
+static gboolean iohandler_source_prepare(GSource *source, gint *timeout)
+{
+ IOHandlerRecord *ioh;
+ IOHandlerSource *s = (IOHandlerSource *)source;
+
+ QLIST_FOREACH(ioh, &s->io_handlers, next) {
+ bool add = false, remove = false;
+
+ if (ioh->deleted) {
+ remove = ioh->attached;
+ } else {
+ int events = 0;
+ if (ioh->fd_read &&
+ (!ioh->fd_read_poll ||
+ ioh->fd_read_poll(ioh->opaque) != 0)) {
+ events |= G_IO_IN | G_IO_HUP | G_IO_ERR;
+ }
+ if (ioh->fd_write) {
+ events |= G_IO_OUT | G_IO_ERR;
+ }
+ ioh->gpfd.events = events,
+
+ remove = !events;
+ add = events && !ioh->attached;
+ }
+ if (remove) {
+ assert(!add);
+ g_source_remove_poll(source, &ioh->gpfd);
+ ioh->attached = false;
+ }
+ if (add) {
+ g_source_add_poll(source, &ioh->gpfd);
+ ioh->attached = true;
+ }
+ }
+ *timeout = -1;
+ return false;
+}
+
+static gboolean iohandler_source_check(GSource *source)
+{
+ IOHandlerRecord *ioh;
+ IOHandlerSource *s = (IOHandlerSource *)source;
+
+ QLIST_FOREACH(ioh, &s->io_handlers, next) {
+ int events;
+ if (!ioh->attached) {
+ continue;
+ }
+ events = ioh->gpfd.revents & ioh->gpfd.events;
+ if (ioh->fd_read &&
+ (events & (G_IO_IN | G_IO_HUP | G_IO_ERR)) &&
+ (!ioh->fd_read_poll || ioh->fd_read_poll(ioh->opaque) != 0)) {
+ return true;
+ }
+ if (ioh->fd_write && (events & (G_IO_OUT | G_IO_ERR))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static gboolean iohandler_source_dispatch(GSource *source,
+ GSourceFunc callback,
+ gpointer data)
+{
+ IOHandlerRecord *pioh, *ioh;
+ IOHandlerSource *s = (IOHandlerSource *)source;
+ int ret = false;
+
+ assert(callback == NULL);
+
+ QLIST_FOREACH_SAFE(ioh, &s->io_handlers, next, pioh) {
+ int revents = 0;
+
+ if (ioh->deleted) {
+ assert(!ioh->attached);
+ } else {
+ revents = ioh->gpfd.events & ioh->gpfd.revents;
+ }
+ if (ioh->fd_read && (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
+ ioh->fd_read(ioh->opaque);
+ ret = true;
+ }
+ if (ioh->fd_write && (revents & (G_IO_OUT | G_IO_ERR))) {
+ ioh->fd_write(ioh->opaque);
+ ret = true;
+ }
+
+ /* Do this last in case read/write handlers marked it for deletion */
+ if (ioh->deleted) {
+ if (ioh->attached) {
+ g_source_remove_poll(source, &ioh->gpfd);
+ }
+ QLIST_REMOVE(ioh, next);
+ g_free(ioh);
+ }
+ }
+ return ret;
+}
+
+static GSourceFuncs iohandler_source_funcs = {
+ iohandler_source_prepare,
+ iohandler_source_check,
+ iohandler_source_dispatch,
+ /* finalize */ NULL
+};
+
+GSource *qemu_iohandler_get_source(void)
+{
+ static IOHandlerSource *ioh_source;
+ if (!ioh_source) {
+ GSource *source = g_source_new(&iohandler_source_funcs,
+ sizeof(IOHandlerSource));
+ ioh_source = (IOHandlerSource *)source;
+ QLIST_INIT(&ioh_source->io_handlers);
+ }
+ return &ioh_source->source;
+}
diff --git a/iohandler.c b/iohandler.c
index cca614f..79982ee 100644
--- a/iohandler.c
+++ b/iohandler.c
@@ -27,26 +27,12 @@
#include "qemu/queue.h"
#include "block/aio.h"
#include "qemu/main-loop.h"
+#include "qemu/iohandler.h"
#ifndef _WIN32
#include <sys/wait.h>
#endif
-typedef struct IOHandlerRecord {
- IOCanReadHandler *fd_read_poll;
- 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);
-
-
/* XXX: fd_read_poll should be suppressed, but an API change is
necessary in the character devices to suppress fd_can_read(). */
int qemu_set_fd_handler2(int fd,
@@ -56,31 +42,33 @@ int qemu_set_fd_handler2(int fd,
void *opaque)
{
IOHandlerRecord *ioh;
+ IOHandlerSource *source = (IOHandlerSource *)qemu_iohandler_get_source();
assert(fd >= 0);
if (!fd_read && !fd_write) {
- QLIST_FOREACH(ioh, &io_handlers, next) {
+ QLIST_FOREACH(ioh, &source->io_handlers, next) {
if (ioh->fd == fd) {
ioh->deleted = 1;
break;
}
}
} else {
- QLIST_FOREACH(ioh, &io_handlers, next) {
+ QLIST_FOREACH(ioh, &source->io_handlers, next) {
if (ioh->fd == fd)
goto found;
}
ioh = g_malloc0(sizeof(IOHandlerRecord));
- QLIST_INSERT_HEAD(&io_handlers, ioh, next);
+ QLIST_INSERT_HEAD(&source->io_handlers, ioh, next);
found:
ioh->fd = fd;
ioh->fd_read_poll = fd_read_poll;
ioh->fd_read = fd_read;
ioh->fd_write = fd_write;
ioh->opaque = opaque;
- ioh->pollfds_idx = -1;
- ioh->deleted = 0;
+ ioh->deleted = false;
+ ioh->attached = false;
+ ioh->gpfd.fd = fd;
qemu_notify_event();
}
return 0;
@@ -94,68 +82,6 @@ int qemu_set_fd_handler(int fd,
return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
}
-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 &&
- (!ioh->fd_read_poll ||
- ioh->fd_read_poll(ioh->opaque) != 0)) {
- 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
diff --git a/main-loop.c b/main-loop.c
index 53393a4..4f81e9f 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -28,6 +28,7 @@
#include "sysemu/qtest.h"
#include "slirp/libslirp.h"
#include "qemu/main-loop.h"
+#include "qemu/iohandler.h"
#include "block/aio.h"
#ifndef _WIN32
@@ -148,6 +149,9 @@ int qemu_init_main_loop(Error **errp)
src = aio_get_g_source(qemu_aio_context);
g_source_attach(src, NULL);
g_source_unref(src);
+ src = qemu_iohandler_get_source();
+ g_source_attach(src, NULL);
+ g_source_unref(src);
return 0;
}
@@ -474,7 +478,6 @@ int main_loop_wait(int nonblocking)
#ifdef CONFIG_SLIRP
slirp_pollfds_fill(gpollfds, &timeout);
#endif
- qemu_iohandler_fill(gpollfds);
if (timeout == UINT32_MAX) {
timeout_ns = -1;
@@ -487,7 +490,6 @@ int main_loop_wait(int nonblocking)
&main_loop_tlg));
ret = os_host_main_loop_wait(timeout_ns);
- qemu_iohandler_poll(gpollfds, ret);
#ifdef CONFIG_SLIRP
slirp_pollfds_poll(gpollfds, (ret < 0));
#endif
--
1.9.3