Just a proof of concept, with the write-side still under the global lock, in order to test the call_rcu code.
Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- iohandler.c | 45 ++++++++++++++++++++------------------------- 1 files changed, 20 insertions(+), 25 deletions(-) diff --git a/iohandler.c b/iohandler.c index 2b82421..4c1f68f 100644 --- a/iohandler.c +++ b/iohandler.c @@ -26,17 +26,18 @@ #include "qemu-common.h" #include "qemu-char.h" #include "qemu-queue.h" +#include "rcu.h" #ifndef _WIN32 #include <sys/wait.h> #endif typedef struct IOHandlerRecord { + struct rcu_head h; int fd; IOCanReadHandler *fd_read_poll; IOHandler *fd_read; IOHandler *fd_write; - int deleted; void *opaque; QLIST_ENTRY(IOHandlerRecord) next; } IOHandlerRecord; @@ -55,28 +56,26 @@ int qemu_set_fd_handler2(int fd, { IOHandlerRecord *ioh; - 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; + //qemu_mutex_lock(&iohandler_lock); + QLIST_FOREACH(ioh, &io_handlers, next) { + if (ioh->fd == fd) { + break; } + } + if (ioh) { + QLIST_REMOVE(ioh, next); + call_rcu(&ioh->h, rcu_free); + } + if (fd_read || fd_write) { ioh = qemu_mallocz(sizeof(IOHandlerRecord)); - QLIST_INSERT_HEAD(&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->deleted = 0; + QLIST_INSERT_HEAD(&io_handlers, ioh, next); } + //qemu_mutex_lock(&iohandler_unlock); return 0; } @@ -92,9 +91,8 @@ void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set * { IOHandlerRecord *ioh; + rcu_read_lock(); QLIST_FOREACH(ioh, &io_handlers, next) { - if (ioh->deleted) - continue; if (ioh->fd_read && (!ioh->fd_read_poll || ioh->fd_read_poll(ioh->opaque) != 0)) { @@ -108,6 +106,7 @@ void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set * *pnfds = ioh->fd; } } + rcu_read_unlock(); } void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int ret) @@ -115,20 +114,16 @@ void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int re if (ret > 0) { IOHandlerRecord *pioh, *ioh; + rcu_read_lock(); QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) { - if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, readfds)) { + if (ioh->fd_read && FD_ISSET(ioh->fd, readfds)) { ioh->fd_read(ioh->opaque); } - if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, writefds)) { + if (ioh->fd_write && FD_ISSET(ioh->fd, writefds)) { ioh->fd_write(ioh->opaque); } - - /* Do this last in case read/write handlers marked it for deletion */ - if (ioh->deleted) { - QLIST_REMOVE(ioh, next); - qemu_free(ioh); - } } + rcu_read_unlock(); } } -- 1.7.6