From: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
To: Paolo Bonzini <pbonzini@redhat.com>
Cc: qemulist@gmail.com, aliguori@us.ibm.com,
Michael Roth <mdroth@linux.vnet.ibm.com>,
stefanha@redhat.com, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH 7/9] iohandler: associate with main event loop via a QSource
Date: Thu, 15 Aug 2013 14:07:21 +0800 [thread overview]
Message-ID: <520C7019.5040309@linux.vnet.ibm.com> (raw)
In-Reply-To: <51876168.60501@redhat.com>
于 2013-5-6 15:53, Paolo Bonzini 写道:
> Il 03/05/2013 18:03, Michael Roth ha scritto:
>> This introduces a GlibQContext wrapper around the main GMainContext
>> event loop, and associates iohandlers with it via a QSource (which
>> GlibQContext creates a GSource from so that it can be driven via
>> GLib. A subsequent patch will drive the GlibQContext directly)
>>
>> We also add "QContext-aware" functionality to iohandler interfaces
>> so that they can be bound to other QContext event loops, and add
>> non-global set_fd_handler() interfaces to facilitate this. This is made
>> possible by simply searching a given QContext for a QSource by the name
>> of "iohandler" so that we can attach event handlers to the associated
>> IOHandlerState.
>>
>> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
>
> This patch is why I think that this is a bit overengineered. The main
> loop is always glib-based, there should be no need to go through the
> QSource abstraction.
>
I thought to use glib-based eventloop before, but found that
AioContext's pending request need to be flushed in release
operation, which can't be done in g_main_context_release. This
brings difficult to do every thing based on glib's API. Do
you think we should stick to QContext to wrap or hide GMainContext?
> BTW, this is broken for Win32. The right thing to do here is to first
> convert iohandler to a GSource in such a way that it works for both
> POSIX and Win32, and then (if needed) we can later convert GSource to
> QSource.
>
> Paolo
>
>> ---
>> include/qemu/main-loop.h | 31 +++++-
>> iohandler.c | 238 ++++++++++++++++++++++++++++++++--------------
>> main-loop.c | 21 +++-
>> 3 files changed, 213 insertions(+), 77 deletions(-)
>>
>> diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
>> index 6f0200a..dbadf9f 100644
>> --- a/include/qemu/main-loop.h
>> +++ b/include/qemu/main-loop.h
>> @@ -26,6 +26,7 @@
>> #define QEMU_MAIN_LOOP_H 1
>>
>> #include "block/aio.h"
>> +#include "qcontext/qcontext.h"
>>
>> #define SIG_IPI SIGUSR1
>>
>> @@ -168,9 +169,24 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
>>
>> /* async I/O support */
>>
>> +#define QSOURCE_IOHANDLER "iohandler"
>> +
>> typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
>> typedef int IOCanReadHandler(void *opaque);
>>
>> +QContext *qemu_get_qcontext(void);
>> +/**
>> + * iohandler_attach: Attach a QSource to a QContext
>> + *
>> + * This enables the use of IOHandler interfaces such as
>> + * set_fd_handler() on the given QContext. IOHandler lists will be
>> + * tracked/handled/dispatched based on a named QSource that is added to
>> + * the QContext
>> + *
>> + * @ctx: A QContext to add an IOHandler QSource to
>> + */
>> +void iohandler_attach(QContext *ctx);
>> +
>> /**
>> * qemu_set_fd_handler2: Register a file descriptor with the main loop
>> *
>> @@ -217,6 +233,13 @@ int qemu_set_fd_handler2(int fd,
>> IOHandler *fd_write,
>> void *opaque);
>>
>> +int set_fd_handler2(QContext *ctx,
>> + int fd,
>> + IOCanReadHandler *fd_read_poll,
>> + IOHandler *fd_read,
>> + IOHandler *fd_write,
>> + void *opaque);
>> +
>> /**
>> * qemu_set_fd_handler: Register a file descriptor with the main loop
>> *
>> @@ -250,6 +273,12 @@ int qemu_set_fd_handler(int fd,
>> IOHandler *fd_write,
>> void *opaque);
>>
>> +int set_fd_handler(QContext *ctx,
>> + int fd,
>> + IOHandler *fd_read,
>> + IOHandler *fd_write,
>> + void *opaque);
>> +
>> #ifdef CONFIG_POSIX
>> /**
>> * qemu_add_child_watch: Register a child process for reaping.
>> @@ -302,8 +331,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.c b/iohandler.c
>> index ae2ef8f..8625272 100644
>> --- a/iohandler.c
>> +++ b/iohandler.c
>> @@ -41,38 +41,170 @@ typedef struct IOHandlerRecord {
>> int fd;
>> int pollfds_idx;
>> bool deleted;
>> + GPollFD pfd;
>> + bool pfd_added;
>> } IOHandlerRecord;
>>
>> -static QLIST_HEAD(, IOHandlerRecord) io_handlers =
>> - QLIST_HEAD_INITIALIZER(io_handlers);
>> +typedef struct IOHandlerState {
>> + QLIST_HEAD(, IOHandlerRecord) io_handlers;
>> +} IOHandlerState;
>>
>> +static bool iohandler_prepare(QSource *qsource, int *timeout)
>> +{
>> + QSourceClass *qsourcek = QSOURCE_GET_CLASS(qsource);
>> + IOHandlerState *s = qsourcek->get_user_data(qsource);
>> + IOHandlerRecord *ioh;
>>
>> -/* 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,
>> - IOCanReadHandler *fd_read_poll,
>> - IOHandler *fd_read,
>> - IOHandler *fd_write,
>> - void *opaque)
>> + QLIST_FOREACH(ioh, &s->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) {
>> + ioh->pfd.fd = ioh->fd;
>> + ioh->pfd.events = events;
>> + if (!ioh->pfd_added) {
>> + qsourcek->add_poll(qsource, &ioh->pfd);
>> + ioh->pfd_added = true;
>> + }
>> + } else {
>> + ioh->pfd.events = 0;
>> + ioh->pfd.revents = 0;
>> + }
>> + }
>> + *timeout = 10;
>> + return false;
>> +}
>> +
>> +static bool iohandler_check(QSource *qsource)
>> {
>> + QSourceClass *sourcek = QSOURCE_GET_CLASS(qsource);
>> + IOHandlerState *s = sourcek->get_user_data(qsource);
>> IOHandlerRecord *ioh;
>>
>> + QLIST_FOREACH(ioh, &s->io_handlers, next) {
>> + if (ioh->deleted) {
>> + continue;
>> + }
>> + if (ioh->pfd.revents) {
>> + return true;
>> + }
>> + }
>> +
>> + return false;
>> +}
>> +
>> +static bool iohandler_dispatch(QSource *qsource)
>> +{
>> + QSourceClass *sourcek = QSOURCE_GET_CLASS(qsource);
>> + IOHandlerState *s = sourcek->get_user_data(qsource);
>> + IOHandlerRecord *pioh, *ioh;
>> +
>> + QLIST_FOREACH_SAFE(ioh, &s->io_handlers, next, pioh) {
>> + int revents = ioh->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) {
>> + if (ioh->pfd_added) {
>> + sourcek->remove_poll(qsource, &ioh->pfd);
>> + }
>> + QLIST_REMOVE(ioh, next);
>> + g_free(ioh);
>> + }
>> + }
>> +
>> + return true;
>> +}
>> +
>> +static void iohandler_finalize(QSource *qsource)
>> +{
>> + QSourceClass *sourcek = QSOURCE_GET_CLASS(qsource);
>> + IOHandlerState *s = sourcek->get_user_data(qsource);
>> + IOHandlerRecord *pioh, *ioh;
>> +
>> + QLIST_FOREACH_SAFE(ioh, &s->io_handlers, next, pioh) {
>> + if (ioh->pfd_added) {
>> + sourcek->remove_poll(qsource, &ioh->pfd);
>> + }
>> + QLIST_REMOVE(ioh, next);
>> + g_free(ioh);
>> + }
>> +
>> + g_free(s);
>> +}
>> +
>> +static const QSourceFuncs iohandler_funcs = {
>> + iohandler_prepare,
>> + iohandler_check,
>> + iohandler_dispatch,
>> + iohandler_finalize,
>> +};
>> +
>> +void iohandler_attach(QContext *ctx)
>> +{
>> + IOHandlerState *s;
>> + QSource *qsource;
>> +
>> + s = g_new0(IOHandlerState, 1);
>> + QLIST_INIT(&s->io_handlers);
>> +
>> + qsource = qsource_new(iohandler_funcs, NULL, QSOURCE_IOHANDLER, s);
>> + qcontext_attach(ctx, qsource, NULL);
>> +}
>> +
>> +int set_fd_handler2(QContext *ctx,
>> + int fd,
>> + IOCanReadHandler *fd_read_poll,
>> + IOHandler *fd_read,
>> + IOHandler *fd_write,
>> + void *opaque)
>> +{
>> + QSourceClass *sourcek;
>> + QSource *source;
>> + IOHandlerState *s;
>> + IOHandlerRecord *ioh;
>> +
>> + source = qcontext_find_source_by_name(ctx, QSOURCE_IOHANDLER);
>> + if (!source) {
>> + assert(0);
>> + }
>> + sourcek = QSOURCE_GET_CLASS(source);
>> + s = sourcek->get_user_data(source);
>> +
>> assert(fd >= 0);
>>
>> if (!fd_read && !fd_write) {
>> - QLIST_FOREACH(ioh, &io_handlers, next) {
>> + QLIST_FOREACH(ioh, &s->io_handlers, next) {
>> if (ioh->fd == fd) {
>> ioh->deleted = 1;
>> break;
>> }
>> }
>> } else {
>> - QLIST_FOREACH(ioh, &io_handlers, next) {
>> + QLIST_FOREACH(ioh, &s->io_handlers, next) {
>> if (ioh->fd == fd)
>> goto found;
>> }
>> ioh = g_malloc0(sizeof(IOHandlerRecord));
>> - QLIST_INSERT_HEAD(&io_handlers, ioh, next);
>> + QLIST_INSERT_HEAD(&s->io_handlers, ioh, next);
>> found:
>> ioh->fd = fd;
>> ioh->fd_read_poll = fd_read_poll;
>> @@ -86,74 +218,34 @@ int qemu_set_fd_handler2(int fd,
>> return 0;
>> }
>>
>> -int qemu_set_fd_handler(int fd,
>> - IOHandler *fd_read,
>> - IOHandler *fd_write,
>> - void *opaque)
>> +int set_fd_handler(QContext *ctx,
>> + int fd,
>> + IOHandler *fd_read,
>> + IOHandler *fd_write,
>> + void *opaque)
>> {
>> - return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
>> + return set_fd_handler2(ctx, fd, NULL, fd_read, fd_write, opaque);
>> }
>>
>> -void qemu_iohandler_fill(GArray *pollfds)
>> +/* 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,
>> + IOCanReadHandler *fd_read_poll,
>> + IOHandler *fd_read,
>> + IOHandler *fd_write,
>> + void *opaque)
>> {
>> - 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;
>> - }
>> - }
>> + return set_fd_handler2(qemu_get_qcontext(), fd,
>> + fd_read_poll, fd_read, fd_write,
>> + opaque);
>> }
>>
>> -void qemu_iohandler_poll(GArray *pollfds, int ret)
>> +int qemu_set_fd_handler(int fd,
>> + IOHandler *fd_read,
>> + IOHandler *fd_write,
>> + void *opaque)
>> {
>> - 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);
>> - }
>> - }
>> - }
>> + return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
>> }
>>
>> /* reaping of zombies. right now we're not passing the status to
>> diff --git a/main-loop.c b/main-loop.c
>> index f46aece..ae284a6 100644
>> --- a/main-loop.c
>> +++ b/main-loop.c
>> @@ -27,6 +27,8 @@
>> #include "slirp/slirp.h"
>> #include "qemu/main-loop.h"
>> #include "block/aio.h"
>> +#include "qcontext/qcontext.h"
>> +#include "qcontext/glib-qcontext.h"
>>
>> #ifndef _WIN32
>>
>> @@ -107,6 +109,13 @@ static int qemu_signal_init(void)
>> }
>> #endif
>>
>> +static QContext *qemu_qcontext;
>> +
>> +QContext *qemu_get_qcontext(void)
>> +{
>> + return qemu_qcontext;
>> +}
>> +
>> static AioContext *qemu_aio_context;
>>
>> AioContext *qemu_get_aio_context(void)
>> @@ -128,6 +137,7 @@ int qemu_init_main_loop(void)
>> {
>> int ret;
>> GSource *src;
>> + Error *err = NULL;
>>
>> init_clocks();
>> if (init_timer_alarm() < 0) {
>> @@ -135,6 +145,15 @@ int qemu_init_main_loop(void)
>> exit(1);
>> }
>>
>> + qemu_qcontext = QCONTEXT(glib_qcontext_new("main", false, &err));
>> + if (err) {
>> + g_warning("error initializing main qcontext");
>> + error_free(err);
>> + return -1;
>> + }
>> +
>> + iohandler_attach(qemu_qcontext);
>> +
>> ret = qemu_signal_init();
>> if (ret) {
>> return ret;
>> @@ -464,9 +483,7 @@ int main_loop_wait(int nonblocking)
>> slirp_update_timeout(&timeout);
>> slirp_pollfds_fill(gpollfds);
>> #endif
>> - qemu_iohandler_fill(gpollfds);
>> ret = os_host_main_loop_wait(timeout);
>> - qemu_iohandler_poll(gpollfds, ret);
>> #ifdef CONFIG_SLIRP
>> slirp_pollfds_poll(gpollfds, (ret < 0));
>> #endif
>>
>
>
--
Best Regards
Wenchao Xia
next prev parent reply other threads:[~2013-08-15 6:08 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-05-03 16:03 [Qemu-devel] [RFC 0/9] QContext: QOM class to support multiple event loops Michael Roth
2013-05-03 16:03 ` [Qemu-devel] [PATCH 1/9] qom: add qom_init_completion Michael Roth
2013-05-06 7:45 ` Paolo Bonzini
2013-05-06 19:01 ` mdroth
2013-05-03 16:03 ` [Qemu-devel] [PATCH 2/9] qom: add object_property_add_unnamed_child Michael Roth
2013-05-06 7:44 ` Paolo Bonzini
2013-05-06 18:48 ` mdroth
2013-05-08 11:33 ` Stefan Hajnoczi
2013-05-03 16:03 ` [Qemu-devel] [PATCH 3/9] QSource: QEMU event source object Michael Roth
2013-05-03 16:03 ` [Qemu-devel] [PATCH 4/9] QContext: QEMU event loop context, abstract base class Michael Roth
2013-05-03 16:03 ` [Qemu-devel] [PATCH 5/9] GlibQContext: a QContext wrapper around GMainContexts Michael Roth
2013-05-03 16:03 ` [Qemu-devel] [PATCH 6/9] QContext: add unit tests Michael Roth
2013-05-03 16:03 ` [Qemu-devel] [PATCH 7/9] iohandler: associate with main event loop via a QSource Michael Roth
2013-05-06 7:53 ` Paolo Bonzini
2013-05-06 19:03 ` mdroth
2013-08-15 6:07 ` Wenchao Xia [this message]
2013-05-03 16:03 ` [Qemu-devel] [PATCH 8/9] main-loop: drive main event loop via QContext Michael Roth
2013-05-03 16:03 ` [Qemu-devel] [PATCH 9/9] dataplane: use a QContext event loop in place of custom thread Michael Roth
2013-05-06 7:54 ` Paolo Bonzini
2013-05-06 19:13 ` mdroth
2013-05-06 3:26 ` [Qemu-devel] [RFC 0/9] QContext: QOM class to support multiple event loops liu ping fan
2013-05-06 18:43 ` mdroth
2013-05-06 7:54 ` Paolo Bonzini
2013-05-06 12:25 ` Anthony Liguori
2013-05-06 18:35 ` mdroth
2013-05-06 20:04 ` Paolo Bonzini
2013-05-06 18:17 ` mdroth
2013-05-08 11:54 ` Stefan Hajnoczi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=520C7019.5040309@linux.vnet.ibm.com \
--to=xiawenc@linux.vnet.ibm.com \
--cc=aliguori@us.ibm.com \
--cc=mdroth@linux.vnet.ibm.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=qemulist@gmail.com \
--cc=stefanha@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).