diff --git a/aio.c b/aio.c
index 2f08655..0d50c87 100644
--- a/aio.c
+++ b/aio.c
@@ -52,14 +52,15 @@ static AioHandler *find_aio_handler(int fd)
     return NULL;
 }
 
-int qemu_aio_set_fd_handler(int fd,
+static int qemu_aio_assign_fd_handler(int fd,
                             IOHandler *io_read,
                             IOHandler *io_write,
                             AioFlushHandler *io_flush,
                             AioProcessQueue *io_process_queue,
-                            void *opaque)
+                            void *opaque, bool system)
 {
     AioHandler *node;
+    int r;
 
     node = find_aio_handler(fd);
 
@@ -93,11 +94,34 @@ int qemu_aio_set_fd_handler(int fd,
         node->opaque = opaque;
     }
 
-    qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque);
-
+    r = system ? qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque) :
+        qemu_set_system_fd_handler(fd, NULL, io_read, io_write, opaque);
+    assert(!r);
     return 0;
 }
 
+int qemu_aio_set_fd_handler(int fd,
+                            IOHandler *io_read,
+                            IOHandler *io_write,
+                            AioFlushHandler *io_flush,
+                            AioProcessQueue *io_process_queue,
+                            void *opaque)
+{
+    return qemu_aio_assign_fd_handler(fd, io_read, io_write, io_flush,
+                                      io_process_queue, opaque, false);
+}
+
+int qemu_aio_set_system_fd_handler(int fd,
+                            IOHandler *io_read,
+                            IOHandler *io_write,
+                            AioFlushHandler *io_flush,
+                            AioProcessQueue *io_process_queue,
+                            void *opaque)
+{
+    return qemu_aio_assign_fd_handler(fd, io_read, io_write, io_flush,
+                                      io_process_queue, opaque, true);
+}
+
 void qemu_aio_flush(void)
 {
     AioHandler *node;
diff --git a/cmd.c b/cmd.c
index db2c9c4..26dcfe4 100644
--- a/cmd.c
+++ b/cmd.c
@@ -154,7 +154,7 @@ static void prep_fetchline(void *opaque)
 {
     int *fetchable = opaque;
 
-    qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
+    qemu_aio_set_system_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
     *fetchable= 1;
 }
 
@@ -202,8 +202,8 @@ command_loop(void)
         if (!prompted) {
             printf("%s", get_prompt());
             fflush(stdout);
-            qemu_aio_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, NULL,
-                                    NULL, &fetchable);
+            qemu_aio_set_system_fd_handler(STDIN_FILENO, prep_fetchline,
+                                           NULL, NULL, NULL, &fetchable);
             prompted = 1;
         }
 
@@ -228,7 +228,7 @@ command_loop(void)
         prompted = 0;
         fetchable = 0;
 	}
-    qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
+    qemu_aio_set_system_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
 }
 
 /* from libxcmd/input.c */
diff --git a/gdbstub.c b/gdbstub.c
index eb8465d..1dd53d9 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2653,7 +2653,7 @@ int gdbserver_start(const char *device)
             sigaction(SIGINT, &act, NULL);
         }
 #endif
-        chr = qemu_chr_open("gdb", device, NULL);
+        chr = qemu_chr_open_system("gdb", device, NULL);
         if (!chr)
             return -1;
 
diff --git a/migration-exec.c b/migration-exec.c
index 14718dd..a8026bf 100644
--- a/migration-exec.c
+++ b/migration-exec.c
@@ -123,7 +123,7 @@ static void exec_accept_incoming_migration(void *opaque)
     QEMUFile *f = opaque;
 
     process_incoming_migration(f);
-    qemu_set_fd_handler2(qemu_stdio_fd(f), NULL, NULL, NULL, NULL);
+    qemu_set_system_fd_handler(qemu_stdio_fd(f), NULL, NULL, NULL, NULL);
     qemu_fclose(f);
 }
 
@@ -138,7 +138,7 @@ int exec_start_incoming_migration(const char *command)
         return -errno;
     }
 
-    qemu_set_fd_handler2(qemu_stdio_fd(f), NULL,
+    qemu_set_system_fd_handler(qemu_stdio_fd(f), NULL,
 			 exec_accept_incoming_migration, NULL, f);
 
     return 0;
diff --git a/migration-fd.c b/migration-fd.c
index 6d14505..e7f8c1f 100644
--- a/migration-fd.c
+++ b/migration-fd.c
@@ -106,7 +106,7 @@ static void fd_accept_incoming_migration(void *opaque)
     QEMUFile *f = opaque;
 
     process_incoming_migration(f);
-    qemu_set_fd_handler2(qemu_stdio_fd(f), NULL, NULL, NULL, NULL);
+    qemu_set_system_fd_handler(qemu_stdio_fd(f), NULL, NULL, NULL, NULL);
     qemu_fclose(f);
 }
 
@@ -124,7 +124,7 @@ int fd_start_incoming_migration(const char *infd)
         return -errno;
     }
 
-    qemu_set_fd_handler2(fd, NULL, fd_accept_incoming_migration, NULL, f);
+    qemu_set_system_fd_handler(fd, NULL, fd_accept_incoming_migration, NULL, f);
 
     return 0;
 }
diff --git a/migration-tcp.c b/migration-tcp.c
index b55f419..7ea0f5b 100644
--- a/migration-tcp.c
+++ b/migration-tcp.c
@@ -66,7 +66,7 @@ static void tcp_wait_for_connect(void *opaque)
         return;
     }
 
-    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+    qemu_set_system_fd_handler(s->fd, NULL, NULL, NULL, NULL);
 
     if (val == 0)
         migrate_fd_connect(s);
@@ -123,7 +123,7 @@ MigrationState *tcp_start_outgoing_migration(Monitor *mon,
             ret = -(s->get_error(s));
 
         if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
-            qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
+            qemu_set_system_fd_handler(s->fd, NULL, NULL, tcp_wait_for_connect, s);
     } while (ret == -EINTR);
 
     if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
@@ -165,7 +165,7 @@ static void tcp_accept_incoming_migration(void *opaque)
 out:
     close(c);
 out2:
-    qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
+    qemu_set_system_fd_handler(s, NULL, NULL, NULL, NULL);
     close(s);
 }
 
@@ -193,7 +193,7 @@ int tcp_start_incoming_migration(const char *host_port)
     if (listen(s, 1) == -1)
         goto err;
 
-    qemu_set_fd_handler2(s, NULL, tcp_accept_incoming_migration, NULL,
+    qemu_set_system_fd_handler(s, NULL, tcp_accept_incoming_migration, NULL,
                          (void *)(unsigned long)s);
 
     return 0;
diff --git a/migration-unix.c b/migration-unix.c
index 57232c0..e32fe6b 100644
--- a/migration-unix.c
+++ b/migration-unix.c
@@ -65,7 +65,7 @@ static void unix_wait_for_connect(void *opaque)
         return;
     }
 
-    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+    qemu_set_system_fd_handler(s->fd, NULL, NULL, NULL, NULL);
 
     if (val == 0)
         migrate_fd_connect(s);
@@ -118,7 +118,7 @@ MigrationState *unix_start_outgoing_migration(Monitor *mon,
 	    ret = -(s->get_error(s));
 
         if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
-	    qemu_set_fd_handler2(s->fd, NULL, NULL, unix_wait_for_connect, s);
+	    qemu_set_system_fd_handler(s->fd, NULL, NULL, unix_wait_for_connect, s);
     } while (ret == -EINTR);
 
     if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
@@ -171,7 +171,7 @@ static void unix_accept_incoming_migration(void *opaque)
     process_incoming_migration(f);
     qemu_fclose(f);
 out:
-    qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
+    qemu_set_system_fd_handler(s, NULL, NULL, NULL, NULL);
     close(s);
     close(c);
 }
@@ -203,7 +203,7 @@ int unix_start_incoming_migration(const char *path)
         goto err;
     }
 
-    qemu_set_fd_handler2(sock, NULL, unix_accept_incoming_migration, NULL,
+    qemu_set_system_fd_handler(sock, NULL, unix_accept_incoming_migration, NULL,
 			 (void *)(unsigned long)sock);
 
     return 0;
diff --git a/migration.c b/migration.c
index 9ee8b17..7597069 100644
--- a/migration.c
+++ b/migration.c
@@ -273,7 +273,7 @@ int migrate_fd_cleanup(FdMigrationState *s)
 {
     int ret = 0;
 
-    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+    qemu_set_system_fd_handler(s->fd, NULL, NULL, NULL, NULL);
 
     if (s->file) {
         DPRINTF("closing file\n");
@@ -300,7 +300,7 @@ void migrate_fd_put_notify(void *opaque)
 {
     FdMigrationState *s = opaque;
 
-    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+    qemu_set_system_fd_handler(s->fd, NULL, NULL, NULL, NULL);
     qemu_file_put_notify(s->file);
 }
 
@@ -317,7 +317,7 @@ ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size)
         ret = -(s->get_error(s));
 
     if (ret == -EAGAIN) {
-        qemu_set_fd_handler2(s->fd, NULL, NULL, migrate_fd_put_notify, s);
+        qemu_set_system_fd_handler(s->fd, NULL, NULL, migrate_fd_put_notify, s);
     } else if (ret < 0) {
         if (s->mon) {
             monitor_resume(s->mon);
@@ -445,6 +445,6 @@ int migrate_fd_close(void *opaque)
 {
     FdMigrationState *s = opaque;
 
-    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+    qemu_set_system_fd_handler(s->fd, NULL, NULL, NULL, NULL);
     return s->close(s);
 }
diff --git a/qemu-aio.h b/qemu-aio.h
index 3bdd749..4223d34 100644
--- a/qemu-aio.h
+++ b/qemu-aio.h
@@ -56,4 +56,11 @@ int qemu_aio_set_fd_handler(int fd,
                             AioProcessQueue *io_process_queue,
                             void *opaque);
 
+/* Same but for system handlers, which run when VM is stopped. */
+int qemu_aio_set_system_fd_handler(int fd,
+                            IOHandler *io_read,
+                            IOHandler *io_write,
+                            AioFlushHandler *io_flush,
+                            AioProcessQueue *io_process_queue,
+                            void *opaque);
 #endif
diff --git a/qemu-char.c b/qemu-char.c
index 88997f9..6a26787 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2500,6 +2500,16 @@ CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*i
     return chr;
 }
 
+CharDriverState *qemu_chr_system_open(const char *label,
+                                      const char *filename, void (*init)(struct CharDriverState *s))
+{
+    CharDriverState *chr = qemu_chr_open(label, filename, init);
+    if (chr) {
+        chr->system = 1;
+    }
+    return chr;
+}
+
 void qemu_chr_close(CharDriverState *chr)
 {
     QTAILQ_REMOVE(&chardevs, chr, next);
diff --git a/qemu-char.h b/qemu-char.h
index 18ad12b..2f35fc9 100644
--- a/qemu-char.h
+++ b/qemu-char.h
@@ -68,6 +68,7 @@ struct CharDriverState {
     char *label;
     char *filename;
     int opened;
+    int system;
     QTAILQ_ENTRY(CharDriverState) next;
 };
 
@@ -75,6 +76,8 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
 CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
                                     void (*init)(struct CharDriverState *s));
 CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s));
+CharDriverState *qemu_chr_system_open(const char *label, const char *filename,
+				      void (*init)(struct CharDriverState *s));
 void qemu_chr_close(CharDriverState *chr);
 void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
     GCC_FMT_ATTR(2, 3);
@@ -111,4 +114,9 @@ int qemu_set_fd_handler(int fd,
                         IOHandler *fd_read,
                         IOHandler *fd_write,
                         void *opaque);
+int qemu_set_system_fd_handler(int fd,
+                         IOCanReadHandler *fd_read_poll,
+                         IOHandler *fd_read,
+                         IOHandler *fd_write,
+                         void *opaque);
 #endif
diff --git a/qemu-kvm.c b/qemu-kvm.c
index 471306b..c99b597 100644
--- a/qemu-kvm.c
+++ b/qemu-kvm.c
@@ -1577,7 +1577,7 @@ int kvm_main_loop(void)
 
     fcntl(sigfd, F_SETFL, O_NONBLOCK);
 
-    qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL,
+    qemu_set_system_fd_handler(sigfd, NULL, sigfd_handler, NULL,
                          (void *)(unsigned long) sigfd);
 
     pthread_cond_broadcast(&qemu_system_cond);
diff --git a/qemu-tool.c b/qemu-tool.c
index 392e1c9..0255ff3 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -111,3 +111,12 @@ int qemu_set_fd_handler2(int fd,
 {
     return 0;
 }
+
+int qemu_set_system_fd_handler(int fd,
+                               IOCanReadHandler *fd_read_poll,
+                               IOHandler *fd_read,
+                               IOHandler *fd_write,
+                               void *opaque)
+{
+    return 0;
+}
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 6c404b3..fdcb303 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -97,7 +97,7 @@ static void watch_update_mask(SpiceWatch *watch, int event_mask)
     if (watch->event_mask & SPICE_WATCH_EVENT_WRITE) {
         on_read = watch_write;
     }
-    qemu_set_fd_handler(watch->fd, on_read, on_write, watch);
+    qemu_set_system_fd_handler(watch->fd, NULL, on_read, on_write, watch);
 }
 
 static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c
index a51ddc8..58f199b 100644
--- a/ui/vnc-auth-sasl.c
+++ b/ui/vnc-auth-sasl.c
@@ -84,7 +84,7 @@ long vnc_client_write_sasl(VncState *vs)
      * SASL encoded output
      */
     if (vs->output.offset == 0) {
-        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+        qemu_set_systemk_fd_handler(vs->csock, NULL, vnc_client_read, NULL, vs);
     }
 
     return ret;
diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c
index 07c1691..489fc11 100644
--- a/ui/vnc-auth-vencrypt.c
+++ b/ui/vnc-auth-vencrypt.c
@@ -71,9 +71,9 @@ static int vnc_start_vencrypt_handshake(struct VncState *vs) {
        if (!gnutls_error_is_fatal(ret)) {
            VNC_DEBUG("Handshake interrupted (blocking)\n");
            if (!gnutls_record_get_direction(vs->tls.session))
-               qemu_set_fd_handler(vs->csock, vnc_tls_handshake_io, NULL, vs);
+               qemu_set_system_fd_handler(vs->csock, NULL, vnc_tls_handshake_io, NULL, vs);
            else
-               qemu_set_fd_handler(vs->csock, NULL, vnc_tls_handshake_io, vs);
+               qemu_set_system_fd_handler(vs->csock, NULL, NULL, vnc_tls_handshake_io, vs);
            return 0;
        }
        VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
@@ -93,7 +93,7 @@ static int vnc_start_vencrypt_handshake(struct VncState *vs) {
 
     VNC_DEBUG("Handshake done, switching to TLS data mode\n");
     vs->tls.wiremode = VNC_WIREMODE_TLS;
-    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
+    qemu_set_system_fd_handler(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
 
     start_auth_vencrypt_subauth(vs);
 
diff --git a/ui/vnc.c b/ui/vnc.c
index 864342e..b7bdddf 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -1005,7 +1005,7 @@ static void vnc_disconnect_start(VncState *vs)
 {
     if (vs->csock == -1)
         return;
-    qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
+    qemu_set_system_fd_handler(vs->csock, NULL, NULL, NULL, NULL);
     closesocket(vs->csock);
     vs->csock = -1;
 }
@@ -1155,7 +1155,7 @@ static long vnc_client_write_plain(VncState *vs)
     vs->output.offset -= ret;
 
     if (vs->output.offset == 0) {
-        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+        qemu_set_system_fd_handler(vs->csock, NULL, vnc_client_read, NULL, vs);
     }
 
     return ret;
@@ -1189,7 +1189,7 @@ void vnc_client_write(void *opaque)
     if (vs->output.offset) {
         vnc_client_write_locked(opaque);
     } else if (vs->csock != -1) {
-        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+        qemu_set_system_fd_handler(vs->csock, NULL, vnc_client_read, NULL, vs);
     }
     vnc_unlock_output(vs);
 }
@@ -1305,7 +1305,7 @@ void vnc_write(VncState *vs, const void *data, size_t len)
     buffer_reserve(&vs->output, len);
 
     if (vs->csock != -1 && buffer_empty(&vs->output)) {
-        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
+        qemu_set_system_fd_handler(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
     }
 
     buffer_append(&vs->output, data, len);
@@ -2369,7 +2369,7 @@ static void vnc_connect(VncDisplay *vd, int csock)
     VNC_DEBUG("New client on socket %d\n", csock);
     dcl->idle = 0;
     socket_set_nonblock(vs->csock);
-    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+    qemu_set_system_fd_handler(vs->csock, NULL, vnc_client_read, NULL, vs);
 
     vnc_client_cache_addr(vs);
     vnc_qmp_event(vs, QEVENT_VNC_CONNECTED);
@@ -2471,7 +2471,7 @@ void vnc_display_close(DisplayState *ds)
         vs->display = NULL;
     }
     if (vs->lsock != -1) {
-        qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
+        qemu_set_system_fd_handler(vs->lsock, NULL, NULL, NULL, NULL);
         close(vs->lsock);
         vs->lsock = -1;
     }
@@ -2736,5 +2736,5 @@ int vnc_display_open(DisplayState *ds, const char *display)
             vs->display = dpy;
         }
     }
-    return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
+    return qemu_set_system_fd_handler(vs->lsock, NULL, vnc_listen_read, NULL, vs);
 }
diff --git a/vl.c b/vl.c
index 37ed560..1d50e00 100644
--- a/vl.c
+++ b/vl.c
@@ -929,34 +929,36 @@ typedef struct IOHandlerRecord {
     QLIST_ENTRY(IOHandlerRecord) next;
 } IOHandlerRecord;
 
-static QLIST_HEAD(, IOHandlerRecord) io_handlers =
-    QLIST_HEAD_INITIALIZER(io_handlers);
+typedef QLIST_HEAD(, IOHandlerRecord) IOHandlerRecordList;
+static IOHandlerRecordList device_io_handlers =
+    QLIST_HEAD_INITIALIZER(device_io_handlers);
 
+static IOHandlerRecordList system_io_handlers =
+    QLIST_HEAD_INITIALIZER(system_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,
-                         IOCanReadHandler *fd_read_poll,
-                         IOHandler *fd_read,
-                         IOHandler *fd_write,
-                         void *opaque)
+static int qemu_assign_fd_handler(int fd,
+                                  IOCanReadHandler *fd_read_poll,
+                                  IOHandler *fd_read,
+                                  IOHandler *fd_write,
+                                  void *opaque,
+                                  IOHandlerRecordList *list)
 {
     IOHandlerRecord *ioh;
 
     if (!fd_read && !fd_write) {
-        QLIST_FOREACH(ioh, &io_handlers, next) {
+        QLIST_FOREACH(ioh, list, next) {
             if (ioh->fd == fd) {
                 ioh->deleted = 1;
                 break;
             }
         }
     } else {
-        QLIST_FOREACH(ioh, &io_handlers, next) {
+        QLIST_FOREACH(ioh, list, next) {
             if (ioh->fd == fd)
                 goto found;
         }
         ioh = qemu_mallocz(sizeof(IOHandlerRecord));
-        QLIST_INSERT_HEAD(&io_handlers, ioh, next);
+        QLIST_INSERT_HEAD(list, ioh, next);
     found:
         ioh->fd = fd;
         ioh->fd_read_poll = fd_read_poll;
@@ -969,6 +971,19 @@ int qemu_set_fd_handler2(int fd,
     return 0;
 }
 
+
+/* 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)
+{
+    return qemu_assign_fd_handler(fd, fd_read_poll, fd_read, fd_write, opaque,
+                                  &device_io_handlers);
+}
+
 int qemu_set_fd_handler(int fd,
                         IOHandler *fd_read,
                         IOHandler *fd_write,
@@ -977,6 +992,18 @@ int qemu_set_fd_handler(int fd,
     return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
 }
 
+int qemu_set_system_fd_handler(int fd,
+                         IOCanReadHandler *fd_read_poll,
+                         IOHandler *fd_read,
+                         IOHandler *fd_write,
+                         void *opaque)
+{
+    qemu_assign_fd_handler(fd, fd_read_poll, fd_read, fd_write, opaque,
+                                  &device_io_handlers);
+    return qemu_assign_fd_handler(fd, fd_read_poll, fd_read, fd_write, opaque,
+                                  &system_io_handlers);
+}
+
 /***********************************************************/
 /* machine registration */
 
@@ -1213,13 +1240,57 @@ void qemu_system_powerdown_request(void)
     qemu_notify_event();
 }
 
-void main_loop_wait(int nonblocking)
+static inline int get_ioh_fds(IOHandlerRecordList *list,
+                              int nfds, fd_set *rfds, fd_set *wfds)
 {
     IOHandlerRecord *ioh;
+    QLIST_FOREACH(ioh, list, next) {
+        if (ioh->deleted)
+            continue;
+        if (ioh->fd_read &&
+            (!ioh->fd_read_poll ||
+             ioh->fd_read_poll(ioh->opaque) != 0)) {
+            FD_SET(ioh->fd, rfds);
+            if (ioh->fd > nfds)
+                nfds = ioh->fd;
+        }
+        if (ioh->fd_write) {
+            FD_SET(ioh->fd, wfds);
+            if (ioh->fd > nfds)
+                nfds = ioh->fd;
+        }
+    }
+    return nfds;
+}
+
+static inline void call_ioh_fds(IOHandlerRecordList *list,
+                                  fd_set *rfds, fd_set *wfds)
+{
+    IOHandlerRecord *ioh, *pioh;
+
+    QLIST_FOREACH_SAFE(ioh, list, next, pioh) {
+        if (ioh->deleted) {
+            QLIST_REMOVE(ioh, next);
+            qemu_free(ioh);
+            continue;
+        }
+        if (ioh->fd_read && FD_ISSET(ioh->fd, rfds)) {
+            ioh->fd_read(ioh->opaque);
+            if (!(ioh->fd_read_poll && ioh->fd_read_poll(ioh->opaque)))
+                FD_CLR(ioh->fd, rfds);
+        }
+        if (ioh->fd_write && FD_ISSET(ioh->fd, wfds)) {
+            ioh->fd_write(ioh->opaque);
+        }
+    }
+}
+void main_loop_wait(int nonblocking)
+{
     fd_set rfds, wfds, xfds;
     int ret, nfds;
     struct timeval tv;
     int timeout;
+    IOHandlerRecordList *handlers;
 
     if (nonblocking)
         timeout = 0;
@@ -1231,64 +1302,47 @@ void main_loop_wait(int nonblocking)
     os_host_main_loop_wait(&timeout);
 
     /* poll any events */
-    /* XXX: separate device handlers from system ones */
     nfds = -1;
     FD_ZERO(&rfds);
     FD_ZERO(&wfds);
     FD_ZERO(&xfds);
-    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)) {
-            FD_SET(ioh->fd, &rfds);
-            if (ioh->fd > nfds)
-                nfds = ioh->fd;
-        }
-        if (ioh->fd_write) {
-            FD_SET(ioh->fd, &wfds);
-            if (ioh->fd > nfds)
-                nfds = ioh->fd;
-        }
-    }
 
-    tv.tv_sec = timeout / 1000;
-    tv.tv_usec = (timeout % 1000) * 1000;
+    if (vm_running) {
 
-    slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
+        nfds = get_ioh_fds(&device_io_handlers, nfds, &rfds, &wfds);
 
-    qemu_mutex_unlock_iothread();
-    ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
-    qemu_mutex_lock_iothread();
-    if (ret > 0) {
-        IOHandlerRecord *pioh;
+        tv.tv_sec = timeout / 1000;
+        tv.tv_usec = (timeout % 1000) * 1000;
 
-        QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
-            if (ioh->deleted) {
-                QLIST_REMOVE(ioh, next);
-                qemu_free(ioh);
-                continue;
-            }
-            if (ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) {
-                ioh->fd_read(ioh->opaque);
-                if (!(ioh->fd_read_poll && ioh->fd_read_poll(ioh->opaque)))
-                    FD_CLR(ioh->fd, &rfds);
-            }
-            if (ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) {
-                ioh->fd_write(ioh->opaque);
-            }
+        slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
+
+        qemu_mutex_unlock_iothread();
+        ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
+        qemu_mutex_lock_iothread();
+        if (ret > 0) {
+            call_ioh_fds(&device_io_handlers, &rfds, &wfds);
         }
-    }
 
-    slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
+        slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
 
-    qemu_run_all_timers();
+        qemu_run_all_timers();
 
-    /* Check bottom-halves last in case any of the earlier events triggered
-       them.  */
-    qemu_bh_poll();
+        /* Check bottom-halves last in case any of the earlier events triggered
+           them.  */
+        qemu_bh_poll();
+    } else {
+        nfds = get_ioh_fds(&system_io_handlers, nfds, &rfds, &wfds);
+
+        tv.tv_sec = timeout / 1000;
+        tv.tv_usec = (timeout % 1000) * 1000;
 
+        qemu_mutex_unlock_iothread();
+        ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
+        qemu_mutex_lock_iothread();
+        if (ret > 0) {
+            call_ioh_fds(&system_io_handlers, &rfds, &wfds);
+        }
+    }
 }
 
 static int vm_can_run(void)
