* [Qemu-devel] [PATCH v2 01/39] janitor: move iovector functions out of cutils.c
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 02/39] build: move cutils.o and qemu-timer-common.o to oslib-obj-y Paolo Bonzini
` (38 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
This removes the dependency of cutils.c on iov.c, and lets us remove
iov.o from several builds.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
Makefile | 2 +-
Makefile.objs | 4 +--
cutils.c | 103 ---------------------------------------------------------
iov.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tests/Makefile | 2 +-
5 file modificati, 107 inserzioni(+), 107 rimozioni(-)
diff --git a/Makefile b/Makefile
index 17e2d58..ca71601 100644
--- a/Makefile
+++ b/Makefile
@@ -161,7 +161,7 @@ qemu-img.o: qemu-img-cmds.h
tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \
qemu-timer-common.o main-loop.o notify.o \
- iohandler.o cutils.o iov.o async.o error.o
+ iohandler.o cutils.o async.o error.o
tools-obj-$(CONFIG_POSIX) += compatfd.o
qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
diff --git a/Makefile.objs b/Makefile.objs
index 9eca179..99a268e 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -92,7 +92,7 @@ common-obj-y += ui/
common-obj-y += bt-host.o bt-vhci.o
common-obj-y += dma-helpers.o
-common-obj-y += iov.o acl.o
+common-obj-y += acl.o
common-obj-$(CONFIG_POSIX) += compatfd.o
common-obj-y += event_notifier.o
common-obj-y += qemu-timer.o qemu-timer-common.o
@@ -113,7 +113,7 @@ endif
user-obj-y =
user-obj-y += envlist.o path.o
user-obj-y += tcg-runtime.o host-utils.o
-user-obj-y += cutils.o iov.o cache-utils.o
+user-obj-y += cutils.o cache-utils.o
user-obj-y += module.o
user-obj-y += qemu-user.o
user-obj-y += $(trace-obj-y)
diff --git a/cutils.c b/cutils.c
index 8edd8fa..6f9f799 100644
--- a/cutils.c
+++ b/cutils.c
@@ -142,109 +142,6 @@ int qemu_fdatasync(int fd)
#endif
}
-/* io vectors */
-
-void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint)
-{
- qiov->iov = g_malloc(alloc_hint * sizeof(struct iovec));
- qiov->niov = 0;
- qiov->nalloc = alloc_hint;
- qiov->size = 0;
-}
-
-void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov)
-{
- int i;
-
- qiov->iov = iov;
- qiov->niov = niov;
- qiov->nalloc = -1;
- qiov->size = 0;
- for (i = 0; i < niov; i++)
- qiov->size += iov[i].iov_len;
-}
-
-void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len)
-{
- assert(qiov->nalloc != -1);
-
- if (qiov->niov == qiov->nalloc) {
- qiov->nalloc = 2 * qiov->nalloc + 1;
- qiov->iov = g_realloc(qiov->iov, qiov->nalloc * sizeof(struct iovec));
- }
- qiov->iov[qiov->niov].iov_base = base;
- qiov->iov[qiov->niov].iov_len = len;
- qiov->size += len;
- ++qiov->niov;
-}
-
-/*
- * Concatenates (partial) iovecs from src to the end of dst.
- * It starts copying after skipping `soffset' bytes at the
- * beginning of src and adds individual vectors from src to
- * dst copies up to `sbytes' bytes total, or up to the end
- * of src if it comes first. This way, it is okay to specify
- * very large value for `sbytes' to indicate "up to the end
- * of src".
- * Only vector pointers are processed, not the actual data buffers.
- */
-void qemu_iovec_concat(QEMUIOVector *dst,
- QEMUIOVector *src, size_t soffset, size_t sbytes)
-{
- int i;
- size_t done;
- struct iovec *siov = src->iov;
- assert(dst->nalloc != -1);
- assert(src->size >= soffset);
- for (i = 0, done = 0; done < sbytes && i < src->niov; i++) {
- if (soffset < siov[i].iov_len) {
- size_t len = MIN(siov[i].iov_len - soffset, sbytes - done);
- qemu_iovec_add(dst, siov[i].iov_base + soffset, len);
- done += len;
- soffset = 0;
- } else {
- soffset -= siov[i].iov_len;
- }
- }
- /* return done; */
-}
-
-void qemu_iovec_destroy(QEMUIOVector *qiov)
-{
- assert(qiov->nalloc != -1);
-
- qemu_iovec_reset(qiov);
- g_free(qiov->iov);
- qiov->nalloc = 0;
- qiov->iov = NULL;
-}
-
-void qemu_iovec_reset(QEMUIOVector *qiov)
-{
- assert(qiov->nalloc != -1);
-
- qiov->niov = 0;
- qiov->size = 0;
-}
-
-size_t qemu_iovec_to_buf(QEMUIOVector *qiov, size_t offset,
- void *buf, size_t bytes)
-{
- return iov_to_buf(qiov->iov, qiov->niov, offset, buf, bytes);
-}
-
-size_t qemu_iovec_from_buf(QEMUIOVector *qiov, size_t offset,
- const void *buf, size_t bytes)
-{
- return iov_from_buf(qiov->iov, qiov->niov, offset, buf, bytes);
-}
-
-size_t qemu_iovec_memset(QEMUIOVector *qiov, size_t offset,
- int fillc, size_t bytes)
-{
- return iov_memset(qiov->iov, qiov->niov, offset, fillc, bytes);
-}
-
/*
* Checks if a buffer is all zeroes
*
diff --git a/iov.c b/iov.c
index c6a66f0..ae17e7d 100644
--- a/iov.c
+++ b/iov.c
@@ -228,3 +228,106 @@ void iov_hexdump(const struct iovec *iov, const unsigned int iov_cnt,
fprintf(fp, "\n");
}
}
+
+/* io vectors */
+
+void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint)
+{
+ qiov->iov = g_malloc(alloc_hint * sizeof(struct iovec));
+ qiov->niov = 0;
+ qiov->nalloc = alloc_hint;
+ qiov->size = 0;
+}
+
+void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov)
+{
+ int i;
+
+ qiov->iov = iov;
+ qiov->niov = niov;
+ qiov->nalloc = -1;
+ qiov->size = 0;
+ for (i = 0; i < niov; i++)
+ qiov->size += iov[i].iov_len;
+}
+
+void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len)
+{
+ assert(qiov->nalloc != -1);
+
+ if (qiov->niov == qiov->nalloc) {
+ qiov->nalloc = 2 * qiov->nalloc + 1;
+ qiov->iov = g_realloc(qiov->iov, qiov->nalloc * sizeof(struct iovec));
+ }
+ qiov->iov[qiov->niov].iov_base = base;
+ qiov->iov[qiov->niov].iov_len = len;
+ qiov->size += len;
+ ++qiov->niov;
+}
+
+/*
+ * Concatenates (partial) iovecs from src to the end of dst.
+ * It starts copying after skipping `soffset' bytes at the
+ * beginning of src and adds individual vectors from src to
+ * dst copies up to `sbytes' bytes total, or up to the end
+ * of src if it comes first. This way, it is okay to specify
+ * very large value for `sbytes' to indicate "up to the end
+ * of src".
+ * Only vector pointers are processed, not the actual data buffers.
+ */
+void qemu_iovec_concat(QEMUIOVector *dst,
+ QEMUIOVector *src, size_t soffset, size_t sbytes)
+{
+ int i;
+ size_t done;
+ struct iovec *siov = src->iov;
+ assert(dst->nalloc != -1);
+ assert(src->size >= soffset);
+ for (i = 0, done = 0; done < sbytes && i < src->niov; i++) {
+ if (soffset < siov[i].iov_len) {
+ size_t len = MIN(siov[i].iov_len - soffset, sbytes - done);
+ qemu_iovec_add(dst, siov[i].iov_base + soffset, len);
+ done += len;
+ soffset = 0;
+ } else {
+ soffset -= siov[i].iov_len;
+ }
+ }
+ /* return done; */
+}
+
+void qemu_iovec_destroy(QEMUIOVector *qiov)
+{
+ assert(qiov->nalloc != -1);
+
+ qemu_iovec_reset(qiov);
+ g_free(qiov->iov);
+ qiov->nalloc = 0;
+ qiov->iov = NULL;
+}
+
+void qemu_iovec_reset(QEMUIOVector *qiov)
+{
+ assert(qiov->nalloc != -1);
+
+ qiov->niov = 0;
+ qiov->size = 0;
+}
+
+size_t qemu_iovec_to_buf(QEMUIOVector *qiov, size_t offset,
+ void *buf, size_t bytes)
+{
+ return iov_to_buf(qiov->iov, qiov->niov, offset, buf, bytes);
+}
+
+size_t qemu_iovec_from_buf(QEMUIOVector *qiov, size_t offset,
+ const void *buf, size_t bytes)
+{
+ return iov_from_buf(qiov->iov, qiov->niov, offset, buf, bytes);
+}
+
+size_t qemu_iovec_memset(QEMUIOVector *qiov, size_t offset,
+ int fillc, size_t bytes)
+{
+ return iov_memset(qiov->iov, qiov->niov, offset, fillc, bytes);
+}
diff --git a/tests/Makefile b/tests/Makefile
index 86c9b79..945c823 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -48,7 +48,7 @@ tests/check-qdict$(EXESUF): tests/check-qdict.o qdict.o qfloat.o qint.o qstring.
tests/check-qlist$(EXESUF): tests/check-qlist.o qlist.o qint.o
tests/check-qfloat$(EXESUF): tests/check-qfloat.o qfloat.o
tests/check-qjson$(EXESUF): tests/check-qjson.o $(qobject-obj-y) $(tools-obj-y)
-tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(coroutine-obj-y) $(tools-obj-y)
+tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(coroutine-obj-y) $(tools-obj-y) iov.o
tests/test-iov$(EXESUF): tests/test-iov.o iov.o
tests/test-qapi-types.c tests/test-qapi-types.h :\
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 02/39] build: move cutils.o and qemu-timer-common.o to oslib-obj-y
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 01/39] janitor: move iovector functions out of cutils.c Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 03/39] compiler: use weak aliases to provide default definitions Paolo Bonzini
` (37 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
Makefile | 3 +--
Makefile.objs | 6 +++---
2 file modificati, 4 inserzioni(+), 5 rimozioni(-)
diff --git a/Makefile b/Makefile
index ca71601..4bfeeab 100644
--- a/Makefile
+++ b/Makefile
@@ -160,8 +160,7 @@ endif
qemu-img.o: qemu-img-cmds.h
tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \
- qemu-timer-common.o main-loop.o notify.o \
- iohandler.o cutils.o async.o error.o
+ main-loop.o notify.o iohandler.o async.o error.o
tools-obj-$(CONFIG_POSIX) += compatfd.o
qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
diff --git a/Makefile.objs b/Makefile.objs
index 99a268e..9e36166 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -19,7 +19,7 @@ universal-obj-y += $(qom-obj-y)
#######################################################################
# oslib-obj-y is code depending on the OS (win32 vs posix)
-oslib-obj-y = osdep.o
+oslib-obj-y = osdep.o cutils.o qemu-timer-common.o
oslib-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o
oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o
@@ -41,7 +41,7 @@ coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o
#######################################################################
# block-obj-y is code used by both qemu system emulation and qemu-img
-block-obj-y = cutils.o iov.o cache-utils.o qemu-option.o module.o async.o
+block-obj-y = iov.o cache-utils.o qemu-option.o module.o async.o
block-obj-y += nbd.o block.o blockjob.o aio.o aes.o qemu-config.o
block-obj-y += qemu-progress.o qemu-sockets.o uri.o notify.o
block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y)
@@ -113,7 +113,7 @@ endif
user-obj-y =
user-obj-y += envlist.o path.o
user-obj-y += tcg-runtime.o host-utils.o
-user-obj-y += cutils.o cache-utils.o
+user-obj-y += cache-utils.o
user-obj-y += module.o
user-obj-y += qemu-user.o
user-obj-y += $(trace-obj-y)
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 03/39] compiler: use weak aliases to provide default definitions
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 01/39] janitor: move iovector functions out of cutils.c Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 02/39] build: move cutils.o and qemu-timer-common.o to oslib-obj-y Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 04/39] sockets: use weak aliases instead of qemu-tool.c Paolo Bonzini
` (36 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
This is simpler and more portable.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
arch_init.h | 2 +-
compiler.h | 11 ++++-------
qmp.c | 3 ++-
3 file modificati, 7 inserzioni(+), 9 rimozioni(-)
diff --git a/arch_init.h b/arch_init.h
index d9c572a..5fc780c 100644
--- a/arch_init.h
+++ b/arch_init.h
@@ -34,6 +34,6 @@ int tcg_available(void);
int kvm_available(void);
int xen_available(void);
-CpuDefinitionInfoList GCC_WEAK_DECL *arch_query_cpu_definitions(Error **errp);
+CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp);
#endif
diff --git a/compiler.h b/compiler.h
index c734a71..58865d6 100644
--- a/compiler.h
+++ b/compiler.h
@@ -50,16 +50,13 @@
# define __printf__ __gnu_printf__
# endif
# endif
-#if defined(_WIN32)
-#define GCC_WEAK __attribute__((weak))
-#define GCC_WEAK_DECL GCC_WEAK
-#else
-#define GCC_WEAK __attribute__((weak))
-#define GCC_WEAK_DECL
-#endif
+# define QEMU_WEAK_ALIAS(newname, oldname) \
+ typeof(oldname) newname __attribute__((weak, alias (#oldname)))
#else
#define GCC_ATTR /**/
#define GCC_FMT_ATTR(n, m)
+#define QEMU_WEAK_ALIAS(newname, oldname) \
+ _Pragma("weak " #newname "=" #oldname)
#endif
#endif /* COMPILER_H */
diff --git a/qmp.c b/qmp.c
index 31bc3bf..df952b6 100644
--- a/qmp.c
+++ b/qmp.c
@@ -466,11 +466,12 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
return prop_list;
}
-CpuDefinitionInfoList GCC_WEAK *arch_query_cpu_definitions(Error **errp)
+static CpuDefinitionInfoList *default_arch_query_cpu_definitions(Error **errp)
{
error_set(errp, QERR_NOT_SUPPORTED);
return NULL;
}
+QEMU_WEAK_ALIAS(arch_query_cpu_definitions, default_arch_query_cpu_definitions);
CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
{
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 04/39] sockets: use weak aliases instead of qemu-tool.c
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (2 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 03/39] compiler: use weak aliases to provide default definitions Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 05/39] fdsets: use weak aliases instead of qemu-tool.c/qemu-user.c Paolo Bonzini
` (35 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
qemu-tool.c has its own (largeish) set of dependencies. Weak aliases
can be placed directly where people use them, and do not contribute
to increasing the dependencies of generic utility files.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
qemu-sockets.c | 7 +++++++
qemu-tool.c | 6 ------
2 file modificati, 7 inserzioni(+), 6 rimozioni(-)
diff --git a/qemu-sockets.c b/qemu-sockets.c
index cfed9c5..225cd0c 100644
--- a/qemu-sockets.c
+++ b/qemu-sockets.c
@@ -967,3 +967,10 @@ int socket_init(void)
#endif
return 0;
}
+
+static int default_monitor_get_fd(Monitor *mon, const char *name, Error **errp)
+{
+ error_setg(errp, "only QEMU supports file descriptor passing");
+ return -1;
+}
+QEMU_WEAK_ALIAS(monitor_get_fd, default_monitor_get_fd);
diff --git a/qemu-tool.c b/qemu-tool.c
index da4c05a..f2f9813 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -38,12 +38,6 @@ const char *qemu_get_vm_name(void)
Monitor *cur_mon;
-int monitor_get_fd(Monitor *mon, const char *name, Error **errp)
-{
- error_setg(errp, "only QEMU supports file descriptor passing");
- return -1;
-}
-
void vm_stop(RunState state)
{
abort();
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 05/39] fdsets: use weak aliases instead of qemu-tool.c/qemu-user.c
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (3 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 04/39] sockets: use weak aliases instead of qemu-tool.c Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-11-15 18:01 ` Stefan Weil
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 06/39] iohandler: add weak alias in qemu-sockets.c, for qemu-ga Paolo Bonzini
` (34 subsequent siblings)
39 siblings, 1 reply; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
cutils.c | 5 -----
osdep.c | 30 ++++++++++++++++++++++++++++++
qemu-common.h | 1 -
qemu-tool.c | 20 --------------------
qemu-user.c | 20 --------------------
5 file modificati, 30 inserzioni(+), 46 rimozioni(-)
diff --git a/cutils.c b/cutils.c
index 6f9f799..4f0692f 100644
--- a/cutils.c
+++ b/cutils.c
@@ -280,11 +280,6 @@ int qemu_parse_fd(const char *param)
return fd;
}
-int qemu_parse_fdset(const char *param)
-{
- return qemu_parse_fd(param);
-}
-
/* round down to the nearest power of 2*/
int64_t pow2floor(int64_t value)
{
diff --git a/osdep.c b/osdep.c
index 3b25297..0061f74 100644
--- a/osdep.c
+++ b/osdep.c
@@ -144,6 +144,11 @@ fail:
errno = serrno;
return -1;
}
+
+static int qemu_parse_fdset(const char *param)
+{
+ return qemu_parse_fd(param);
+}
#endif
/*
@@ -404,3 +409,28 @@ bool fips_get_state(void)
{
return fips_enabled;
}
+
+
+static int default_fdset_get_fd(int64_t fdset_id, int flags)
+{
+ return -1;
+}
+QEMU_WEAK_ALIAS(monitor_fdset_get_fd, default_fdset_get_fd);
+
+static int default_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
+{
+ return -1;
+}
+QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_add, default_fdset_dup_fd_add);
+
+static int default_fdset_dup_fd_remove(int dup_fd)
+{
+ return -1;
+}
+QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_remove, default_fdset_dup_fd_remove);
+
+static int default_fdset_dup_fd_find(int dup_fd)
+{
+ return -1;
+}
+QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_find, default_fdset_dup_fd_find);
diff --git a/qemu-common.h b/qemu-common.h
index b54612b..36ce522 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -167,7 +167,6 @@ int qemu_fls(int i);
int qemu_fdatasync(int fd);
int fcntl_setfl(int fd, int flag);
int qemu_parse_fd(const char *param);
-int qemu_parse_fdset(const char *param);
/*
* strtosz() suffixes used to specify the default treatment of an
diff --git a/qemu-tool.c b/qemu-tool.c
index f2f9813..84273ae 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -68,26 +68,6 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
{
}
-int monitor_fdset_get_fd(int64_t fdset_id, int flags)
-{
- return -1;
-}
-
-int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
-{
- return -1;
-}
-
-int monitor_fdset_dup_fd_remove(int dup_fd)
-{
- return -1;
-}
-
-int monitor_fdset_dup_fd_find(int dup_fd)
-{
- return -1;
-}
-
int64_t cpu_get_clock(void)
{
return qemu_get_clock_ns(rt_clock);
diff --git a/qemu-user.c b/qemu-user.c
index 13fb9ae..08ccb0f 100644
--- a/qemu-user.c
+++ b/qemu-user.c
@@ -35,23 +35,3 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
void monitor_set_error(Monitor *mon, QError *qerror)
{
}
-
-int monitor_fdset_get_fd(int64_t fdset_id, int flags)
-{
- return -1;
-}
-
-int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
-{
- return -1;
-}
-
-int monitor_fdset_dup_fd_remove(int dup_fd)
-{
- return -1;
-}
-
-int monitor_fdset_dup_fd_find(int dup_fd)
-{
- return -1;
-}
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 05/39] fdsets: use weak aliases instead of qemu-tool.c/qemu-user.c
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 05/39] fdsets: use weak aliases instead of qemu-tool.c/qemu-user.c Paolo Bonzini
@ 2012-11-15 18:01 ` Stefan Weil
2012-11-15 20:52 ` Paolo Bonzini
0 siblings, 1 reply; 62+ messages in thread
From: Stefan Weil @ 2012-11-15 18:01 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: Blue Swirl, aliguori, qemu-devel, stefanha
Am 31.10.2012 16:30, schrieb Paolo Bonzini:
> Signed-off-by: Paolo Bonzini<pbonzini@redhat.com>
> ---
> cutils.c | 5 -----
> osdep.c | 30 ++++++++++++++++++++++++++++++
> qemu-common.h | 1 -
> qemu-tool.c | 20 --------------------
> qemu-user.c | 20 --------------------
> 5 file modificati, 30 inserzioni(+), 46 rimozioni(-)
>
> diff --git a/cutils.c b/cutils.c
> index 6f9f799..4f0692f 100644
> --- a/cutils.c
> +++ b/cutils.c
> @@ -280,11 +280,6 @@ int qemu_parse_fd(const char *param)
> return fd;
> }
>
> -int qemu_parse_fdset(const char *param)
> -{
> - return qemu_parse_fd(param);
> -}
> -
> /* round down to the nearest power of 2*/
> int64_t pow2floor(int64_t value)
> {
> diff --git a/osdep.c b/osdep.c
> index 3b25297..0061f74 100644
> --- a/osdep.c
> +++ b/osdep.c
> @@ -144,6 +144,11 @@ fail:
> errno = serrno;
> return -1;
> }
> +
> +static int qemu_parse_fdset(const char *param)
> +{
> + return qemu_parse_fd(param);
> +}
> #endif
>
> /*
> @@ -404,3 +409,28 @@ bool fips_get_state(void)
> {
> return fips_enabled;
> }
> +
> +
> +static int default_fdset_get_fd(int64_t fdset_id, int flags)
> +{
> + return -1;
> +}
> +QEMU_WEAK_ALIAS(monitor_fdset_get_fd, default_fdset_get_fd);
> +
> +static int default_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
> +{
> + return -1;
> +}
> +QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_add, default_fdset_dup_fd_add);
> +
> +static int default_fdset_dup_fd_remove(int dup_fd)
> +{
> + return -1;
> +}
> +QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_remove, default_fdset_dup_fd_remove);
> +
> +static int default_fdset_dup_fd_find(int dup_fd)
> +{
> + return -1;
> +}
> +QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_find, default_fdset_dup_fd_find);
> diff --git a/qemu-common.h b/qemu-common.h
> index b54612b..36ce522 100644
> --- a/qemu-common.h
> +++ b/qemu-common.h
> @@ -167,7 +167,6 @@ int qemu_fls(int i);
> int qemu_fdatasync(int fd);
> int fcntl_setfl(int fd, int flag);
> int qemu_parse_fd(const char *param);
> -int qemu_parse_fdset(const char *param);
>
> /*
> * strtosz() suffixes used to specify the default treatment of an
> diff --git a/qemu-tool.c b/qemu-tool.c
> index f2f9813..84273ae 100644
> --- a/qemu-tool.c
> +++ b/qemu-tool.c
> @@ -68,26 +68,6 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
> {
> }
>
> -int monitor_fdset_get_fd(int64_t fdset_id, int flags)
> -{
> - return -1;
> -}
> -
> -int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
> -{
> - return -1;
> -}
> -
> -int monitor_fdset_dup_fd_remove(int dup_fd)
> -{
> - return -1;
> -}
> -
> -int monitor_fdset_dup_fd_find(int dup_fd)
> -{
> - return -1;
> -}
> -
> int64_t cpu_get_clock(void)
> {
> return qemu_get_clock_ns(rt_clock);
> diff --git a/qemu-user.c b/qemu-user.c
> index 13fb9ae..08ccb0f 100644
> --- a/qemu-user.c
> +++ b/qemu-user.c
> @@ -35,23 +35,3 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
> void monitor_set_error(Monitor *mon, QError *qerror)
> {
> }
> -
> -int monitor_fdset_get_fd(int64_t fdset_id, int flags)
> -{
> - return -1;
> -}
> -
> -int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
> -{
> - return -1;
> -}
> -
> -int monitor_fdset_dup_fd_remove(int dup_fd)
> -{
> - return -1;
> -}
> -
> -int monitor_fdset_dup_fd_find(int dup_fd)
> -{
> - return -1;
> -}
Hi Paolo,
this patch breaks QEMU on 32 and 64 bit hosts, native and with Wine.
It's easy to reproduce the SIGSEGV crash: just add a -snapshot option.
Obviously the critical code is executed only when this option was used.
Here is a simple command line using Wine:
wine i386-softmmu/qemu-system-i386 -L pc-bios -snapshot Makefile
The disk image does not matter, so I just selected QEMU's Makefile.
It looks like weak symbols are not really working with MinGW
(Blue Swirl previously pointed out that only ELF and a.out are
officially supported).
I can see in the debugger that QEMU wants to call monitor_fdset_dup_fd_find
from qemu_close.
In previous versions, this was just a dummy function returning 0.
Now, it is the function in monitor.c, but the address does not match
exactly, so the code addresses lines near the beginning of
monitor_fdset_dup_fd_find which does not work of course.
A trivial workaround is calling default_fdset_dup_fd_find which
restores the old behaviour. I expect that all other weak functions
would show the same problem if they were used.
Regards,
Stefan
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 05/39] fdsets: use weak aliases instead of qemu-tool.c/qemu-user.c
2012-11-15 18:01 ` Stefan Weil
@ 2012-11-15 20:52 ` Paolo Bonzini
2012-11-15 22:18 ` Stefan Weil
0 siblings, 1 reply; 62+ messages in thread
From: Paolo Bonzini @ 2012-11-15 20:52 UTC (permalink / raw)
To: Stefan Weil; +Cc: Blue Swirl, aliguori, qemu-devel, stefanha
Il 15/11/2012 19:01, Stefan Weil ha scritto:
> Hi Paolo,
>
> this patch breaks QEMU on 32 and 64 bit hosts, native and with Wine.
> It's easy to reproduce the SIGSEGV crash: just add a -snapshot option.
> Obviously the critical code is executed only when this option was used.
I cannot reproduce this, so it must be an assembler or linker bug.
Can you try the alternative code that is used for Mac OS X?
Paolo
> Here is a simple command line using Wine:
>
> wine i386-softmmu/qemu-system-i386 -L pc-bios -snapshot Makefile
>
> The disk image does not matter, so I just selected QEMU's Makefile.
>
> It looks like weak symbols are not really working with MinGW
> (Blue Swirl previously pointed out that only ELF and a.out are
> officially supported).
>
> I can see in the debugger that QEMU wants to call monitor_fdset_dup_fd_find
> from qemu_close.
>
> In previous versions, this was just a dummy function returning 0.
> Now, it is the function in monitor.c, but the address does not match
> exactly, so the code addresses lines near the beginning of
> monitor_fdset_dup_fd_find which does not work of course.
>
> A trivial workaround is calling default_fdset_dup_fd_find which
> restores the old behaviour. I expect that all other weak functions
> would show the same problem if they were used.
>
> Regards,
>
> Stefan
>
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 05/39] fdsets: use weak aliases instead of qemu-tool.c/qemu-user.c
2012-11-15 20:52 ` Paolo Bonzini
@ 2012-11-15 22:18 ` Stefan Weil
2012-11-16 9:35 ` Paolo Bonzini
0 siblings, 1 reply; 62+ messages in thread
From: Stefan Weil @ 2012-11-15 22:18 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: Blue Swirl, aliguori, qemu-devel, stefanha
Am 15.11.2012 21:52, schrieb Paolo Bonzini:
> Il 15/11/2012 19:01, Stefan Weil ha scritto:
>> Hi Paolo,
>>
>> this patch breaks QEMU on 32 and 64 bit hosts, native and with Wine.
>> It's easy to reproduce the SIGSEGV crash: just add a -snapshot option.
>> Obviously the critical code is executed only when this option was used.
>
> I cannot reproduce this, so it must be an assembler or linker bug.
>
> Can you try the alternative code that is used for Mac OS X?
>
> Paolo
The code which is used for Mac OS X also compiles and
results in the same run-time bug with Wine:
wine: Unhandled page fault on write access to 0x00000004 at address
0x7b845d6e (thread 001b), starting debugger...
(immediately after BIOS says "Booting from hard disk...")
This was the modification used:
diff --git a/compiler.h b/compiler.h
index 55d7d74..62427e4 100644
--- a/compiler.h
+++ b/compiler.h
@@ -50,11 +50,12 @@
# define __printf__ __gnu_printf__
# endif
# endif
-# if defined(__APPLE__)
+# if defined(__APPLE__) || defined(_WIN32)
# define QEMU_WEAK_ALIAS(newname, oldname) \
static typeof(oldname) weak_##newname __attribute__((unused,
weakref(#oldname)))
# define QEMU_WEAK_REF(newname, oldname) (weak_##newname ?
weak_##newname : oldname)
# else
+#error
# define QEMU_WEAK_ALIAS(newname, oldname) \
typeof(oldname) newname __attribute__((weak, alias (#oldname)))
# define QEMU_WEAK_REF(newname, oldname) newname
These are my Debian packages (only the 32 bit ones are needed for the test):
ii binutils-mingw-w64-i686
2.22-7+2 Cross-binutils for Win32 (x86) using
MinGW-w64
ii binutils-mingw-w64-x86-64
2.22-7+2 Cross-binutils for Win64 (x64) using
MinGW-w64
ii gcc-mingw-w64
4.6.3-8+7 GNU C compiler for MinGW-w64
ii gcc-mingw-w64-base
4.6.3-8+7 GNU Compiler Collection for MinGW-w64
(base package)
ii gcc-mingw-w64-i686
4.6.3-8+7 GNU C compiler for MinGW-w64
targeting Win32
ii gcc-mingw-w64-x86-64
4.6.3-8+7 GNU C compiler for MinGW-w64
targeting Win64
ii mingw-w64
3.0~svn4933-1 Development environment targetting
32- and 64-bit Windows
ii mingw-w64-dev
3.0~svn4933-1 Development files for MinGW-w64
ii mingw-w64-tools
3.0~svn4933-1 Development tools for 32- and 64-bit
Windows
On Windows, I used a rather new MinGW standard installation.
I'll run more tests with other Linux distributions tomorrow.
Cheers,
Stefan
>> Here is a simple command line using Wine:
>>
>> wine i386-softmmu/qemu-system-i386 -L pc-bios -snapshot Makefile
>>
>> The disk image does not matter, so I just selected QEMU's Makefile.
>>
>> It looks like weak symbols are not really working with MinGW
>> (Blue Swirl previously pointed out that only ELF and a.out are
>> officially supported).
>>
>> I can see in the debugger that QEMU wants to call monitor_fdset_dup_fd_find
>> from qemu_close.
>>
>> In previous versions, this was just a dummy function returning 0.
>> Now, it is the function in monitor.c, but the address does not match
>> exactly, so the code addresses lines near the beginning of
>> monitor_fdset_dup_fd_find which does not work of course.
>>
>> A trivial workaround is calling default_fdset_dup_fd_find which
>> restores the old behaviour. I expect that all other weak functions
>> would show the same problem if they were used.
>>
>> Regards,
>>
>> Stefan
>>
>>
>
>
^ permalink raw reply related [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 05/39] fdsets: use weak aliases instead of qemu-tool.c/qemu-user.c
2012-11-15 22:18 ` Stefan Weil
@ 2012-11-16 9:35 ` Paolo Bonzini
2012-11-16 17:15 ` Stefan Weil
2012-11-16 17:52 ` Peter Maydell
0 siblings, 2 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-11-16 9:35 UTC (permalink / raw)
To: Stefan Weil; +Cc: Blue Swirl, aliguori, qemu-devel, stefanha
Il 15/11/2012 23:18, Stefan Weil ha scritto:
> Am 15.11.2012 21:52, schrieb Paolo Bonzini:
>> Il 15/11/2012 19:01, Stefan Weil ha scritto:
>>> Hi Paolo,
>>>
>>> this patch breaks QEMU on 32 and 64 bit hosts, native and with Wine.
>>> It's easy to reproduce the SIGSEGV crash: just add a -snapshot option.
>>> Obviously the critical code is executed only when this option was used.
>>
>> I cannot reproduce this, so it must be an assembler or linker bug.
>>
>> Can you try the alternative code that is used for Mac OS X?
>
> The code which is used for Mac OS X also compiles and
> results in the same run-time bug with Wine:
Ok, I reproduced the original binutils bug, and found a typo in the
weakrefs implementation. Does this work for you?
diff --git a/compiler.h b/compiler.h
index 55d7d74..d552757 100644
--- a/compiler.h
+++ b/compiler.h
@@ -50,11 +50,12 @@
# define __printf__ __gnu_printf__
# endif
# endif
-# if defined(__APPLE__)
+# if defined(__APPLE__) || defined(_WIN32)
# define QEMU_WEAK_ALIAS(newname, oldname) \
- static typeof(oldname) weak_##newname __attribute__((unused, weakref(#oldname)))
+ static typeof(oldname) weak_##newname __attribute__((unused, weakref(#newname)))
# define QEMU_WEAK_REF(newname, oldname) (weak_##newname ? weak_##newname : oldname)
# else
+#error
# define QEMU_WEAK_ALIAS(newname, oldname) \
typeof(oldname) newname __attribute__((weak, alias (#oldname)))
# define QEMU_WEAK_REF(newname, oldname) newname
If it still doesn't work, let's make sure that this reduced testcase works
for you:
g1.c:
#include <stdio.h>
int f() { printf("strong"); return 82; }
int g() { printf("strong"); return 83; }
g2.c:
#include <stdio.h>
static int weak_f() { return 42; }
static int weak_g() { return 43; }
typeof(weak_f) f __attribute__((__weak__, __alias__("weak_f")));
typeof(weak_g) g __attribute__((__weak__, __alias__("weak_g")));
int main() { printf("%d/%d\n", f(), g()); }
g3.c:
#include <stdio.h>
static int default_f() { return 42; }
static int default_g() { return 43; }
static typeof(default_f) weak_f __attribute__((__weakref__("f")));
static typeof(default_g) weak_g __attribute__((__weakref__("g")));
int main() { printf("%d/%d\n", (weak_f?:default_f)(), (weak_g?:default_g)()); }
Output should be:
- 42/43 for "gcc g2.c"
- 42/43 for "gcc g3.c"
- strongstrong82/83 for "gcc g1.c g2.c"
- strongstrong82/83 for "gcc g1.c g3.c"
Output on Windows is:
- 42/42 for "gcc g2.c"
- 42/43 for "gcc g3.c"
- segfault for "gcc g1.c g2.c"
- strongstrong82/83 for "gcc g1.c g3.c"
So, indeed "normal" weak symbols are broken, but weakrefs seem to work.
If the above patch doesn't work, and/or the reduced testcase fails,
please send to me:
- the .exe for "gcc g1.c g3.c"
- the .s file for g3.s
- the .o file for osdep.o
- the linked .exe (I assume both the windows and console versions fail)
- perhaps the .s file for osdep too; add --save-temps to the compiler command line to get it
Paolo
^ permalink raw reply related [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 05/39] fdsets: use weak aliases instead of qemu-tool.c/qemu-user.c
2012-11-16 9:35 ` Paolo Bonzini
@ 2012-11-16 17:15 ` Stefan Weil
2012-11-16 17:39 ` Paolo Bonzini
2012-11-16 17:52 ` Peter Maydell
1 sibling, 1 reply; 62+ messages in thread
From: Stefan Weil @ 2012-11-16 17:15 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: Blue Swirl, aliguori, qemu-devel, stefanha
Am 16.11.2012 10:35, schrieb Paolo Bonzini:
> Il 15/11/2012 23:18, Stefan Weil ha scritto:
>> Am 15.11.2012 21:52, schrieb Paolo Bonzini:
>>> Il 15/11/2012 19:01, Stefan Weil ha scritto:
>>>> Hi Paolo,
>>>>
>>>> this patch breaks QEMU on 32 and 64 bit hosts, native and with Wine.
>>>> It's easy to reproduce the SIGSEGV crash: just add a -snapshot option.
>>>> Obviously the critical code is executed only when this option was used.
>>>
>>> I cannot reproduce this, so it must be an assembler or linker bug.
>>>
>>> Can you try the alternative code that is used for Mac OS X?
>>
>> The code which is used for Mac OS X also compiles and
>> results in the same run-time bug with Wine:
>
> Ok, I reproduced the original binutils bug, and found a typo in the
> weakrefs implementation. Does this work for you?
>
> diff --git a/compiler.h b/compiler.h
> index 55d7d74..d552757 100644
> --- a/compiler.h
> +++ b/compiler.h
> @@ -50,11 +50,12 @@
> # define __printf__ __gnu_printf__
> # endif
> # endif
> -# if defined(__APPLE__)
> +# if defined(__APPLE__) || defined(_WIN32)
> # define QEMU_WEAK_ALIAS(newname, oldname) \
> - static typeof(oldname) weak_##newname __attribute__((unused, weakref(#oldname)))
> + static typeof(oldname) weak_##newname __attribute__((unused, weakref(#newname)))
> # define QEMU_WEAK_REF(newname, oldname) (weak_##newname ? weak_##newname : oldname)
> # else
> +#error
> # define QEMU_WEAK_ALIAS(newname, oldname) \
> typeof(oldname) newname __attribute__((weak, alias (#oldname)))
> # define QEMU_WEAK_REF(newname, oldname) newname
>
>
> If it still doesn't work, let's make sure that this reduced testcase works
> for you:
Tested-by: Stefan Weil <sw@weilnetz.de>
Great, the above patch fixes w32/w64 (native and with Wine).
Is this modification needed / does it work with MacOS X, too?
With the reduced testcase, I get the same results as in your test.
Regards
Stefan
>
> g1.c:
> #include<stdio.h>
> int f() { printf("strong"); return 82; }
> int g() { printf("strong"); return 83; }
>
> g2.c:
> #include<stdio.h>
> static int weak_f() { return 42; }
> static int weak_g() { return 43; }
> typeof(weak_f) f __attribute__((__weak__, __alias__("weak_f")));
> typeof(weak_g) g __attribute__((__weak__, __alias__("weak_g")));
> int main() { printf("%d/%d\n", f(), g()); }
>
> g3.c:
> #include<stdio.h>
> static int default_f() { return 42; }
> static int default_g() { return 43; }
> static typeof(default_f) weak_f __attribute__((__weakref__("f")));
> static typeof(default_g) weak_g __attribute__((__weakref__("g")));
> int main() { printf("%d/%d\n", (weak_f?:default_f)(), (weak_g?:default_g)()); }
>
> Output should be:
> - 42/43 for "gcc g2.c"
> - 42/43 for "gcc g3.c"
> - strongstrong82/83 for "gcc g1.c g2.c"
> - strongstrong82/83 for "gcc g1.c g3.c"
>
> Output on Windows is:
> - 42/42 for "gcc g2.c"
> - 42/43 for "gcc g3.c"
> - segfault for "gcc g1.c g2.c"
> - strongstrong82/83 for "gcc g1.c g3.c"
>
> So, indeed "normal" weak symbols are broken, but weakrefs seem to work.
>
> If the above patch doesn't work, and/or the reduced testcase fails,
> please send to me:
>
> - the .exe for "gcc g1.c g3.c"
> - the .s file for g3.s
> - the .o file for osdep.o
> - the linked .exe (I assume both the windows and console versions fail)
> - perhaps the .s file for osdep too; add --save-temps to the compiler command line to get it
>
> Paolo
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 05/39] fdsets: use weak aliases instead of qemu-tool.c/qemu-user.c
2012-11-16 17:15 ` Stefan Weil
@ 2012-11-16 17:39 ` Paolo Bonzini
0 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-11-16 17:39 UTC (permalink / raw)
To: Stefan Weil; +Cc: Blue Swirl, aliguori, qemu-devel, stefanha
Il 16/11/2012 18:15, Stefan Weil ha scritto:
>
> Tested-by: Stefan Weil <sw@weilnetz.de>
>
> Great, the above patch fixes w32/w64 (native and with Wine).
> Is this modification needed / does it work with MacOS X, too?
Yes, but I found a way to get rid of weak references completely. The
testing is still precious---thanks very much.
> With the reduced testcase, I get the same results as in your test.
Good to know, too. :) llvm-gcc totally botches it on Mac OS X, by the
way (while clang works there).
Paolo
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 05/39] fdsets: use weak aliases instead of qemu-tool.c/qemu-user.c
2012-11-16 9:35 ` Paolo Bonzini
2012-11-16 17:15 ` Stefan Weil
@ 2012-11-16 17:52 ` Peter Maydell
2012-11-16 17:55 ` Paolo Bonzini
1 sibling, 1 reply; 62+ messages in thread
From: Peter Maydell @ 2012-11-16 17:52 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: Blue Swirl, Stefan Weil, aliguori, qemu-devel, stefanha
On 16 November 2012 09:35, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Ok, I reproduced the original binutils bug, and found a typo in the
> weakrefs implementation. Does this work for you?
>
> diff --git a/compiler.h b/compiler.h
> index 55d7d74..d552757 100644
> --- a/compiler.h
> +++ b/compiler.h
> @@ -50,11 +50,12 @@
> # define __printf__ __gnu_printf__
> # endif
> # endif
> -# if defined(__APPLE__)
> +# if defined(__APPLE__) || defined(_WIN32)
> # define QEMU_WEAK_ALIAS(newname, oldname) \
> - static typeof(oldname) weak_##newname __attribute__((unused, weakref(#oldname)))
> + static typeof(oldname) weak_##newname __attribute__((unused, weakref(#newname)))
> # define QEMU_WEAK_REF(newname, oldname) (weak_##newname ? weak_##newname : oldname)
> # else
> +#error
> # define QEMU_WEAK_ALIAS(newname, oldname) \
> typeof(oldname) newname __attribute__((weak, alias (#oldname)))
> # define QEMU_WEAK_REF(newname, oldname) newname
This change makes compilation fail with clang:
LINK qemu-ga
Undefined symbols for architecture x86_64:
"_monitor_fdset_dup_fd_add", referenced from:
_qemu_open in osdep.o
"_monitor_fdset_dup_fd_remove", referenced from:
_qemu_close in osdep.o
"_monitor_fdset_get_fd", referenced from:
_qemu_open in osdep.o
"_monitor_get_fd", referenced from:
_socket_connect in qemu-sockets.o
_socket_listen in qemu-sockets.o
"_qemu_set_fd_handler2", referenced from:
_inet_connect_addr in qemu-sockets.o
_unix_connect_opts in qemu-sockets.o
_wait_for_connect in qemu-sockets.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
(clang builds OK with current git master.)
-- PMM
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 05/39] fdsets: use weak aliases instead of qemu-tool.c/qemu-user.c
2012-11-16 17:52 ` Peter Maydell
@ 2012-11-16 17:55 ` Paolo Bonzini
0 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-11-16 17:55 UTC (permalink / raw)
To: Peter Maydell; +Cc: Blue Swirl, Stefan Weil, aliguori, qemu-devel, stefanha
Il 16/11/2012 18:52, Peter Maydell ha scritto:
> clang: error: linker command failed with exit code 1 (use -v to see invocation)
>
> (clang builds OK with current git master.)
But I have no idea why, or whether the generated code is correct...
Looks like the safest bet is to go with the good old static library.
Paolo
^ permalink raw reply [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 06/39] iohandler: add weak alias in qemu-sockets.c, for qemu-ga
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (4 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 05/39] fdsets: use weak aliases instead of qemu-tool.c/qemu-user.c Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 07/39] win32: add weak version of qemu_fd_register Paolo Bonzini
` (33 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
qemu-sockets.c | 11 +++++++++++
1 file modificato, 11 inserzioni(+)
diff --git a/qemu-sockets.c b/qemu-sockets.c
index 225cd0c..f2a6371 100644
--- a/qemu-sockets.c
+++ b/qemu-sockets.c
@@ -974,3 +974,14 @@ static int default_monitor_get_fd(Monitor *mon, const char *name, Error **errp)
return -1;
}
QEMU_WEAK_ALIAS(monitor_get_fd, default_monitor_get_fd);
+
+static int default_qemu_set_fd_handler2(int fd,
+ IOCanReadHandler *fd_read_poll,
+ IOHandler *fd_read,
+ IOHandler *fd_write,
+ void *opaque)
+
+{
+ abort();
+}
+QEMU_WEAK_ALIAS(qemu_set_fd_handler2, default_qemu_set_fd_handler2);
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 07/39] win32: add weak version of qemu_fd_register
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (5 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 06/39] iohandler: add weak alias in qemu-sockets.c, for qemu-ga Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 08/39] qemu-timer: make initialization functions idempotent Paolo Bonzini
` (32 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
oslib-win32.c | 5 +++++
1 file modificato, 5 inserzioni(+)
diff --git a/oslib-win32.c b/oslib-win32.c
index 51b33e8..9ca83df 100644
--- a/oslib-win32.c
+++ b/oslib-win32.c
@@ -150,3 +150,8 @@ int qemu_get_thread_id(void)
{
return GetCurrentThreadId();
}
+
+static void default_qemu_fd_register(int fd)
+{
+}
+QEMU_WEAK_ALIAS(qemu_fd_register, default_qemu_fd_register);
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 08/39] qemu-timer: make initialization functions idempotent
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (6 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 07/39] win32: add weak version of qemu_fd_register Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 09/39] main-loop: unify qemu_init_main_loop between QEMU and tools Paolo Bonzini
` (31 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
qemu-timer.c | 12 +++++++++---
1 file modificato, 9 inserzioni(+), 3 rimozioni(-)
diff --git a/qemu-timer.c b/qemu-timer.c
index 908a103..b71e9a6 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -430,9 +430,11 @@ void qemu_unregister_clock_reset_notifier(QEMUClock *clock, Notifier *notifier)
void init_clocks(void)
{
- rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME);
- vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL);
- host_clock = qemu_new_clock(QEMU_CLOCK_HOST);
+ if (!rt_clock) {
+ rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME);
+ vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL);
+ host_clock = qemu_new_clock(QEMU_CLOCK_HOST);
+ }
}
uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts)
@@ -745,6 +747,10 @@ int init_timer_alarm(void)
struct qemu_alarm_timer *t = NULL;
int i, err = -1;
+ if (alarm_timer) {
+ return 0;
+ }
+
for (i = 0; alarm_timers[i].name; i++) {
t = &alarm_timers[i];
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 09/39] main-loop: unify qemu_init_main_loop between QEMU and tools
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (7 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 08/39] qemu-timer: make initialization functions idempotent Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 10/39] qemu-tool: do not depend on qemu-timer.c Paolo Bonzini
` (30 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
main-loop.c | 5 ++++-
main-loop.h | 10 ----------
qemu-tool.c | 7 -------
vl.c | 5 -----
4 file modificati, 4 inserzioni(+), 23 rimozioni(-)
diff --git a/main-loop.c b/main-loop.c
index eb3b6e6..baefe41 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -199,10 +199,13 @@ static int qemu_signal_init(void)
}
#endif
-int main_loop_init(void)
+int qemu_init_main_loop(void)
{
int ret;
+ init_clocks();
+ init_timer_alarm();
+
qemu_mutex_lock_iothread();
ret = qemu_signal_init();
if (ret) {
diff --git a/main-loop.h b/main-loop.h
index dce1cd9..91a0aff 100644
--- a/main-loop.h
+++ b/main-loop.h
@@ -43,16 +43,6 @@
int qemu_init_main_loop(void);
/**
- * main_loop_init: Initializes main loop
- *
- * Internal (but shared for compatibility reasons) initialization routine
- * for the main loop. This should not be used by applications directly,
- * use qemu_init_main_loop() instead.
- *
- */
-int main_loop_init(void);
-
-/**
* main_loop_wait: Run one iteration of the main loop.
*
* If @nonblocking is true, poll for events, otherwise suspend until
diff --git a/qemu-tool.c b/qemu-tool.c
index 84273ae..28a4e8d 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -92,13 +92,6 @@ void qemu_clock_warp(QEMUClock *clock)
{
}
-int qemu_init_main_loop(void)
-{
- init_clocks();
- init_timer_alarm();
- return main_loop_init();
-}
-
void slirp_update_timeout(uint32_t *timeout)
{
}
diff --git a/vl.c b/vl.c
index 9f99ef4..b3186fa 100644
--- a/vl.c
+++ b/vl.c
@@ -2357,11 +2357,6 @@ static void free_and_trace(gpointer mem)
free(mem);
}
-int qemu_init_main_loop(void)
-{
- return main_loop_init();
-}
-
int main(int argc, char **argv, char **envp)
{
int i;
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 10/39] qemu-tool: do not depend on qemu-timer.c
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (8 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 09/39] main-loop: unify qemu_init_main_loop between QEMU and tools Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 11/39] build: opts-visitor is not really part of QAPI Paolo Bonzini
` (29 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
qemu-tool.c | 2 +-
1 file modificato, 1 inserzione(+). 1 rimozione(-)
diff --git a/qemu-tool.c b/qemu-tool.c
index 28a4e8d..b46631e 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -70,7 +70,7 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
int64_t cpu_get_clock(void)
{
- return qemu_get_clock_ns(rt_clock);
+ return get_clock_realtime();
}
int64_t cpu_get_icount(void)
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 11/39] build: opts-visitor is not really part of QAPI
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (9 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 10/39] qemu-tool: do not depend on qemu-timer.c Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 12/39] build: do not include main loop where it is not actually used Paolo Bonzini
` (28 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
It is only used by QEMU itself, do not build it into the tests.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
qapi/Makefile.objs | 4 +++-
1 file modificato, 3 inserzioni(+). 1 rimozione(-)
diff --git a/qapi/Makefile.objs b/qapi/Makefile.objs
index 5f5846e..f9bd3b9 100644
--- a/qapi/Makefile.objs
+++ b/qapi/Makefile.objs
@@ -1,3 +1,5 @@
qapi-obj-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o
qapi-obj-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o
-qapi-obj-y += string-input-visitor.o string-output-visitor.o opts-visitor.o
+qapi-obj-y += string-input-visitor.o string-output-visitor.o
+
+common-obj-y += opts-visitor.o
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 12/39] build: do not include main loop where it is not actually used
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (10 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 11/39] build: opts-visitor is not really part of QAPI Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 13/39] event_notifier: add Win32 implementation Paolo Bonzini
` (27 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
Makefile | 6 +++---
Makefile.objs | 5 ++---
tests/Makefile | 8 ++++----
3 file modificati, 9 inserzioni(+), 10 rimozioni(-)
diff --git a/Makefile b/Makefile
index 4bfeeab..3ff63df 100644
--- a/Makefile
+++ b/Makefile
@@ -160,7 +160,7 @@ endif
qemu-img.o: qemu-img-cmds.h
tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \
- main-loop.o notify.o iohandler.o async.o error.o
+ main-loop.o iohandler.o error.o
tools-obj-$(CONFIG_POSIX) += compatfd.o
qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
@@ -169,7 +169,7 @@ qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
-vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) $(tools-obj-y) qemu-timer-common.o libcacard/vscclient.o
+vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) libcacard/vscclient.o
$(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^ $(libcacard_libs) $(LIBS)," LINK $@")
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y)
@@ -212,7 +212,7 @@ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
-qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(tools-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y)
+qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(oslib-obj-y) $(trace-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y)
QEMULIBS=libuser libdis libdis-user
diff --git a/Makefile.objs b/Makefile.objs
index 9e36166..54daa9f 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -228,9 +228,8 @@ universal-obj-y += $(qapi-obj-y)
######################################################################
# guest agent
-qga-obj-y = qga/ qemu-ga.o module.o
-qga-obj-$(CONFIG_WIN32) += oslib-win32.o
-qga-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-sockets.o qemu-option.o
+qga-obj-y = qga/ qemu-ga.o module.o qemu-tool.o
+qga-obj-$(CONFIG_POSIX) += qemu-sockets.o qemu-option.o
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/tests/Makefile b/tests/Makefile
index 945c823..9bf0765 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -36,7 +36,7 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \
tests/test-qmp-commands.o tests/test-visitor-serialization.o
-test-qapi-obj-y = $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y)
+test-qapi-obj-y = $(qobject-obj-y) $(qapi-obj-y) qemu-tool.o
test-qapi-obj-y += tests/test-qapi-visit.o tests/test-qapi-types.o
test-qapi-obj-y += module.o
@@ -47,8 +47,8 @@ tests/check-qstring$(EXESUF): tests/check-qstring.o qstring.o
tests/check-qdict$(EXESUF): tests/check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o
tests/check-qlist$(EXESUF): tests/check-qlist.o qlist.o qint.o
tests/check-qfloat$(EXESUF): tests/check-qfloat.o qfloat.o
-tests/check-qjson$(EXESUF): tests/check-qjson.o $(qobject-obj-y) $(tools-obj-y)
-tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(coroutine-obj-y) $(tools-obj-y) iov.o
+tests/check-qjson$(EXESUF): tests/check-qjson.o $(qobject-obj-y) qemu-tool.o
+tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(coroutine-obj-y) $(tools-obj-y) $(block-obj-y) iov.o
tests/test-iov$(EXESUF): tests/test-iov.o iov.o
tests/test-qapi-types.c tests/test-qapi-types.h :\
@@ -81,7 +81,7 @@ TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))
QTEST_TARGETS=$(foreach TARGET,$(TARGETS), $(if $(check-qtest-$(TARGET)-y), $(TARGET),))
check-qtest-$(CONFIG_POSIX)=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y))
-qtest-obj-y = tests/libqtest.o $(oslib-obj-y) $(tools-obj-y)
+qtest-obj-y = tests/libqtest.o $(oslib-obj-y)
$(check-qtest-y): $(qtest-obj-y)
.PHONY: check-help
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 13/39] event_notifier: add Win32 implementation
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (11 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 12/39] build: do not include main loop where it is not actually used Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 14/39] event_notifier: enable it to use pipes Paolo Bonzini
` (26 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
Makefile.objs | 3 +-
event_notifier.c => event_notifier-posix.c | 0
event_notifier-win32.c | 59 ++++++++++++++++++++++++++++++
event_notifier.h | 17 ++++++++-
qemu-os-win32.h | 1 -
5 file modificati, 76 inserzioni(+), 4 rimozioni(-)
rename event_notifier.c => event_notifier-posix.c (100%)
create mode 100644 event_notifier-win32.c
diff --git a/Makefile.objs b/Makefile.objs
index 54daa9f..5b39c33 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -94,7 +94,8 @@ common-obj-y += bt-host.o bt-vhci.o
common-obj-y += dma-helpers.o
common-obj-y += acl.o
common-obj-$(CONFIG_POSIX) += compatfd.o
-common-obj-y += event_notifier.o
+common-obj-$(CONFIG_POSIX) += event_notifier-posix.o
+common-obj-$(CONFIG_WIN32) += event_notifier-win32.o
common-obj-y += qemu-timer.o qemu-timer-common.o
common-obj-y += qtest.o
common-obj-y += vl.o
diff --git a/event_notifier.c b/event_notifier-posix.c
similarity index 100%
rename from event_notifier.c
rename to event_notifier-posix.c
diff --git a/event_notifier-win32.c b/event_notifier-win32.c
new file mode 100644
index 0000000..c723dad
--- /dev/null
+++ b/event_notifier-win32.c
@@ -0,0 +1,59 @@
+/*
+ * event notifier support
+ *
+ * Copyright Red Hat, Inc. 2010
+ *
+ * Authors:
+ * Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+#include "event_notifier.h"
+#include "main-loop.h"
+
+int event_notifier_init(EventNotifier *e, int active)
+{
+ e->event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ assert(e->event);
+ return 0;
+}
+
+void event_notifier_cleanup(EventNotifier *e)
+{
+ CloseHandle(e->event);
+}
+
+HANDLE event_notifier_get_handle(EventNotifier *e)
+{
+ return e->event;
+}
+
+int event_notifier_set_handler(EventNotifier *e,
+ EventNotifierHandler *handler)
+{
+ if (handler) {
+ return qemu_add_wait_object(e->event, (IOHandler *)handler, e);
+ } else {
+ qemu_del_wait_object(e->event, (IOHandler *)handler, e);
+ return 0;
+ }
+}
+
+int event_notifier_set(EventNotifier *e)
+{
+ SetEvent(e->event);
+ return 0;
+}
+
+int event_notifier_test_and_clear(EventNotifier *e)
+{
+ int ret = WaitForSingleObject(e->event, 0);
+ if (ret == WAIT_OBJECT_0) {
+ ResetEvent(e->event);
+ return true;
+ }
+ return false;
+}
diff --git a/event_notifier.h b/event_notifier.h
index f0ec2f2..b283a49 100644
--- a/event_notifier.h
+++ b/event_notifier.h
@@ -15,18 +15,31 @@
#include "qemu-common.h"
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
struct EventNotifier {
+#ifdef _WIN32
+ HANDLE event;
+#else
int fd;
+#endif
};
typedef void EventNotifierHandler(EventNotifier *);
-void event_notifier_init_fd(EventNotifier *, int fd);
int event_notifier_init(EventNotifier *, int active);
void event_notifier_cleanup(EventNotifier *);
-int event_notifier_get_fd(EventNotifier *);
int event_notifier_set(EventNotifier *);
int event_notifier_test_and_clear(EventNotifier *);
int event_notifier_set_handler(EventNotifier *, EventNotifierHandler *);
+#ifdef CONFIG_POSIX
+void event_notifier_init_fd(EventNotifier *, int fd);
+int event_notifier_get_fd(EventNotifier *);
+#else
+HANDLE event_notifier_get_handle(EventNotifier *);
+#endif
+
#endif
diff --git a/qemu-os-win32.h b/qemu-os-win32.h
index 8ba466d..d0e9234 100644
--- a/qemu-os-win32.h
+++ b/qemu-os-win32.h
@@ -28,7 +28,6 @@
#include <windows.h>
#include <winsock2.h>
-#include "main-loop.h"
/* Workaround for older versions of MinGW. */
#ifndef ECONNREFUSED
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 14/39] event_notifier: enable it to use pipes
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (12 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 13/39] event_notifier: add Win32 implementation Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 15/39] vl: init main loop earlier Paolo Bonzini
` (25 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
This takes the eventfd emulation code from the main loop. When the
EventNotifier is used for the main loop too, we need this compatibility
code.
Without CONFIG_EVENTFD, event_notifier_get_fd is only usable for the
"read" side of the notifier, for example to set a select() handler.
The return value of event_notifier_set changes to the cleaner 0/-errno.
No caller is actually checking the return value.
Reviewed-by: Anthony Liguori <anthony@codemonkey.ws>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
event_notifier-posix.c | 85 ++++++++++++++++++++++++++++++++++++++++----------
event_notifier.h | 3 +-
2 file modificati, 71 inserzioni(+), 17 rimozioni(-)
diff --git a/event_notifier-posix.c b/event_notifier-posix.c
index 2c207e1..6f3239a 100644
--- a/event_notifier-posix.c
+++ b/event_notifier-posix.c
@@ -20,48 +20,101 @@
void event_notifier_init_fd(EventNotifier *e, int fd)
{
- e->fd = fd;
+ e->rfd = fd;
+ e->wfd = fd;
}
int event_notifier_init(EventNotifier *e, int active)
{
+ int fds[2];
+ int ret;
+
#ifdef CONFIG_EVENTFD
- int fd = eventfd(!!active, EFD_NONBLOCK | EFD_CLOEXEC);
- if (fd < 0)
- return -errno;
- e->fd = fd;
- return 0;
+ ret = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
#else
- return -ENOSYS;
+ ret = -1;
+ errno = ENOSYS;
#endif
+ if (ret >= 0) {
+ e->rfd = e->wfd = ret;
+ } else {
+ if (errno != ENOSYS) {
+ return -errno;
+ }
+ if (qemu_pipe(fds) < 0) {
+ return -errno;
+ }
+ ret = fcntl_setfl(fds[0], O_NONBLOCK);
+ if (ret < 0) {
+ ret = -errno;
+ goto fail;
+ }
+ ret = fcntl_setfl(fds[1], O_NONBLOCK);
+ if (ret < 0) {
+ ret = -errno;
+ goto fail;
+ }
+ e->rfd = fds[0];
+ e->wfd = fds[1];
+ }
+ if (active) {
+ event_notifier_set(e);
+ }
+ return 0;
+
+fail:
+ close(fds[0]);
+ close(fds[1]);
+ return ret;
}
void event_notifier_cleanup(EventNotifier *e)
{
- close(e->fd);
+ if (e->rfd != e->wfd) {
+ close(e->rfd);
+ }
+ close(e->wfd);
}
int event_notifier_get_fd(EventNotifier *e)
{
- return e->fd;
+ return e->rfd;
}
int event_notifier_set_handler(EventNotifier *e,
EventNotifierHandler *handler)
{
- return qemu_set_fd_handler(e->fd, (IOHandler *)handler, NULL, e);
+ return qemu_set_fd_handler(e->rfd, (IOHandler *)handler, NULL, e);
}
int event_notifier_set(EventNotifier *e)
{
- uint64_t value = 1;
- int r = write(e->fd, &value, sizeof(value));
- return r == sizeof(value);
+ static const uint64_t value = 1;
+ ssize_t ret;
+
+ do {
+ ret = write(e->wfd, &value, sizeof(value));
+ } while (ret < 0 && errno == EINTR);
+
+ /* EAGAIN is fine, a read must be pending. */
+ if (ret < 0 && errno != EAGAIN) {
+ return -errno;
+ }
+ return 0;
}
int event_notifier_test_and_clear(EventNotifier *e)
{
- uint64_t value;
- int r = read(e->fd, &value, sizeof(value));
- return r == sizeof(value);
+ int value;
+ ssize_t len;
+ char buffer[512];
+
+ /* Drain the notify pipe. For eventfd, only 8 bytes will be read. */
+ value = 0;
+ do {
+ len = read(e->rfd, buffer, sizeof(buffer));
+ value |= (len > 0);
+ } while ((len == -1 && errno == EINTR) || len == sizeof(buffer));
+
+ return value;
}
diff --git a/event_notifier.h b/event_notifier.h
index b283a49..88b57af 100644
--- a/event_notifier.h
+++ b/event_notifier.h
@@ -23,7 +23,8 @@ struct EventNotifier {
#ifdef _WIN32
HANDLE event;
#else
- int fd;
+ int rfd;
+ int wfd;
#endif
};
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 15/39] vl: init main loop earlier
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (13 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 14/39] event_notifier: enable it to use pipes Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-11-02 7:26 ` Jan Kiszka
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 16/39] aio: change qemu_aio_set_fd_handler to return void Paolo Bonzini
` (24 subsequent siblings)
39 siblings, 1 reply; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Otherwise, chardevs will not be able to create a bottom half as soon
as that will require an AioContext.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
vl.c | 12 ++++++------
1 file modificato, 6 inserzioni(+), 6 rimozioni(-)
diff --git a/vl.c b/vl.c
index b3186fa..f84e969 100644
--- a/vl.c
+++ b/vl.c
@@ -3311,6 +3311,12 @@ int main(int argc, char **argv, char **envp)
}
loc_set_none();
+ qemu_init_cpu_loop();
+ if (qemu_init_main_loop()) {
+ fprintf(stderr, "qemu_init_main_loop failed\n");
+ exit(1);
+ }
+
if (qemu_opts_foreach(qemu_find_opts("sandbox"), parse_sandbox, NULL, 0)) {
exit(1);
}
@@ -3463,12 +3469,6 @@ int main(int argc, char **argv, char **envp)
configure_accelerator();
- qemu_init_cpu_loop();
- if (qemu_init_main_loop()) {
- fprintf(stderr, "qemu_init_main_loop failed\n");
- exit(1);
- }
-
machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
if (machine_opts) {
kernel_filename = qemu_opt_get(machine_opts, "kernel");
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 15/39] vl: init main loop earlier
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 15/39] vl: init main loop earlier Paolo Bonzini
@ 2012-11-02 7:26 ` Jan Kiszka
2012-11-02 9:55 ` Paolo Bonzini
0 siblings, 1 reply; 62+ messages in thread
From: Jan Kiszka @ 2012-11-02 7:26 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: aliguori, qemu-devel, stefanha
[-- Attachment #1: Type: text/plain, Size: 1546 bytes --]
On 2012-10-31 16:30, Paolo Bonzini wrote:
> Otherwise, chardevs will not be able to create a bottom half as soon
> as that will require an AioContext.
>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
> vl.c | 12 ++++++------
> 1 file modificato, 6 inserzioni(+), 6 rimozioni(-)
>
> diff --git a/vl.c b/vl.c
> index b3186fa..f84e969 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -3311,6 +3311,12 @@ int main(int argc, char **argv, char **envp)
> }
> loc_set_none();
>
> + qemu_init_cpu_loop();
> + if (qemu_init_main_loop()) {
> + fprintf(stderr, "qemu_init_main_loop failed\n");
> + exit(1);
> + }
> +
> if (qemu_opts_foreach(qemu_find_opts("sandbox"), parse_sandbox, NULL, 0)) {
> exit(1);
> }
> @@ -3463,12 +3469,6 @@ int main(int argc, char **argv, char **envp)
>
> configure_accelerator();
>
> - qemu_init_cpu_loop();
> - if (qemu_init_main_loop()) {
> - fprintf(stderr, "qemu_init_main_loop failed\n");
> - exit(1);
> - }
> -
> machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
> if (machine_opts) {
> kernel_filename = qemu_opt_get(machine_opts, "kernel");
>
This breaks daemonize as the BQL is marked as owned by the father
process. See also [1] in this context.
Can we move os_daemonize before that, or what are its dependencies? I
have an increasingly bad feeling about this code shuffling.
Jan
[1] http://thread.gmane.org/gmane.comp.emulators.qemu/179311
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 259 bytes --]
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 15/39] vl: init main loop earlier
2012-11-02 7:26 ` Jan Kiszka
@ 2012-11-02 9:55 ` Paolo Bonzini
2012-11-02 10:32 ` Jan Kiszka
0 siblings, 1 reply; 62+ messages in thread
From: Paolo Bonzini @ 2012-11-02 9:55 UTC (permalink / raw)
To: Jan Kiszka; +Cc: aliguori, qemu-devel, stefanha
Il 02/11/2012 08:26, Jan Kiszka ha scritto:
> Can we move os_daemonize before that, or what are its dependencies? I
> have an increasingly bad feeling about this code shuffling.
Moving os_daemonize too early ruins error messages. I would just
pull qemu_mutex_lock_iothread later, even just before cpu_exec_init_all.
Something like this (untested):
diff --git a/main-loop.c b/main-loop.c
index e43c7c8..07c4b84 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -125,7 +125,6 @@ int qemu_init_main_loop(void)
init_clocks();
init_timer_alarm();
- qemu_mutex_lock_iothread();
ret = qemu_signal_init();
if (ret) {
return ret;
diff --git a/vl.c b/vl.c
index 99681da..210d525 100644
--- a/vl.c
+++ b/vl.c
@@ -3631,13 +3631,6 @@ int main(int argc, char **argv, char **envp)
}
#endif
- os_daemonize();
-
- if (pid_file && qemu_create_pidfile(pid_file) != 0) {
- os_pidfile_error();
- exit(1);
- }
-
/* init the memory */
if (ram_size == 0) {
ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
@@ -3682,11 +3675,6 @@ int main(int argc, char **argv, char **envp)
os_set_line_buffering();
-#ifdef CONFIG_SPICE
- /* spice needs the timers to be initialized by this point */
- qemu_spice_init();
-#endif
-
if (icount_option && (kvm_enabled() || xen_enabled())) {
fprintf(stderr, "-icount is not allowed with kvm or xen\n");
exit(1);
@@ -3709,6 +3697,20 @@ int main(int argc, char **argv, char **envp)
}
}
+ os_daemonize();
+
+ if (pid_file && qemu_create_pidfile(pid_file) != 0) {
+ os_pidfile_error();
+ exit(1);
+ }
+
+ qemu_mutex_lock_iothread();
+
+#ifdef CONFIG_SPICE
+ /* spice needs timers & threads to be initialized by this point */
+ qemu_spice_init();
+#endif
+
cpu_exec_init_all();
bdrv_init_with_whitelist();
^ permalink raw reply related [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 15/39] vl: init main loop earlier
2012-11-02 9:55 ` Paolo Bonzini
@ 2012-11-02 10:32 ` Jan Kiszka
2012-11-02 11:04 ` Paolo Bonzini
0 siblings, 1 reply; 62+ messages in thread
From: Jan Kiszka @ 2012-11-02 10:32 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: aliguori, qemu-devel, stefanha
On 2012-11-02 10:55, Paolo Bonzini wrote:
> Il 02/11/2012 08:26, Jan Kiszka ha scritto:
>> Can we move os_daemonize before that, or what are its dependencies? I
>> have an increasingly bad feeling about this code shuffling.
>
> Moving os_daemonize too early ruins error messages. I would just
> pull qemu_mutex_lock_iothread later, even just before cpu_exec_init_all.
> Something like this (untested):
>
> diff --git a/main-loop.c b/main-loop.c
> index e43c7c8..07c4b84 100644
> --- a/main-loop.c
> +++ b/main-loop.c
> @@ -125,7 +125,6 @@ int qemu_init_main_loop(void)
> init_clocks();
> init_timer_alarm();
>
> - qemu_mutex_lock_iothread();
> ret = qemu_signal_init();
> if (ret) {
> return ret;
> diff --git a/vl.c b/vl.c
> index 99681da..210d525 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -3631,13 +3631,6 @@ int main(int argc, char **argv, char **envp)
> }
> #endif
>
> - os_daemonize();
> -
> - if (pid_file && qemu_create_pidfile(pid_file) != 0) {
> - os_pidfile_error();
> - exit(1);
> - }
> -
> /* init the memory */
> if (ram_size == 0) {
> ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
> @@ -3682,11 +3675,6 @@ int main(int argc, char **argv, char **envp)
>
> os_set_line_buffering();
>
> -#ifdef CONFIG_SPICE
> - /* spice needs the timers to be initialized by this point */
> - qemu_spice_init();
> -#endif
> -
> if (icount_option && (kvm_enabled() || xen_enabled())) {
> fprintf(stderr, "-icount is not allowed with kvm or xen\n");
> exit(1);
> @@ -3709,6 +3697,20 @@ int main(int argc, char **argv, char **envp)
> }
> }
>
> + os_daemonize();
> +
> + if (pid_file && qemu_create_pidfile(pid_file) != 0) {
> + os_pidfile_error();
> + exit(1);
> + }
> +
> + qemu_mutex_lock_iothread();
> +
> +#ifdef CONFIG_SPICE
> + /* spice needs timers & threads to be initialized by this point */
> + qemu_spice_init();
> +#endif
> +
> cpu_exec_init_all();
>
> bdrv_init_with_whitelist();
>
Would have been too easy:
# qemu-system-x86_64 -daemonize
gettime: Invalid argument
Internal timer error: aborting
Haven't looked at details yet.
Jan
--
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 15/39] vl: init main loop earlier
2012-11-02 10:32 ` Jan Kiszka
@ 2012-11-02 11:04 ` Paolo Bonzini
0 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-11-02 11:04 UTC (permalink / raw)
To: Jan Kiszka; +Cc: aliguori, qemu-devel, stefanha
Il 02/11/2012 11:32, Jan Kiszka ha scritto:
> On 2012-11-02 10:55, Paolo Bonzini wrote:
>> Il 02/11/2012 08:26, Jan Kiszka ha scritto:
>>> Can we move os_daemonize before that, or what are its dependencies? I
>>> have an increasingly bad feeling about this code shuffling.
>>
>> Moving os_daemonize too early ruins error messages. I would just
>> pull qemu_mutex_lock_iothread later, even just before cpu_exec_init_all.
>> Something like this (untested):
>>
>> diff --git a/main-loop.c b/main-loop.c
>> index e43c7c8..07c4b84 100644
>> --- a/main-loop.c
>> +++ b/main-loop.c
>> @@ -125,7 +125,6 @@ int qemu_init_main_loop(void)
>> init_clocks();
>> init_timer_alarm();
>>
>> - qemu_mutex_lock_iothread();
>> ret = qemu_signal_init();
>> if (ret) {
>> return ret;
>> diff --git a/vl.c b/vl.c
>> index 99681da..210d525 100644
>> --- a/vl.c
>> +++ b/vl.c
>> @@ -3631,13 +3631,6 @@ int main(int argc, char **argv, char **envp)
>> }
>> #endif
>>
>> - os_daemonize();
>> -
>> - if (pid_file && qemu_create_pidfile(pid_file) != 0) {
>> - os_pidfile_error();
>> - exit(1);
>> - }
>> -
>> /* init the memory */
>> if (ram_size == 0) {
>> ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
>> @@ -3682,11 +3675,6 @@ int main(int argc, char **argv, char **envp)
>>
>> os_set_line_buffering();
>>
>> -#ifdef CONFIG_SPICE
>> - /* spice needs the timers to be initialized by this point */
>> - qemu_spice_init();
>> -#endif
>> -
>> if (icount_option && (kvm_enabled() || xen_enabled())) {
>> fprintf(stderr, "-icount is not allowed with kvm or xen\n");
>> exit(1);
>> @@ -3709,6 +3697,20 @@ int main(int argc, char **argv, char **envp)
>> }
>> }
>>
>> + os_daemonize();
>> +
>> + if (pid_file && qemu_create_pidfile(pid_file) != 0) {
>> + os_pidfile_error();
>> + exit(1);
>> + }
>> +
>> + qemu_mutex_lock_iothread();
>> +
>> +#ifdef CONFIG_SPICE
>> + /* spice needs timers & threads to be initialized by this point */
>> + qemu_spice_init();
>> +#endif
>> +
>> cpu_exec_init_all();
>>
>> bdrv_init_with_whitelist();
>>
>
> Would have been too easy:
>
> # qemu-system-x86_64 -daemonize
> gettime: Invalid argument
> Internal timer error: aborting
>
> Haven't looked at details yet.
np, will do so now.
Paolo
^ permalink raw reply [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 16/39] aio: change qemu_aio_set_fd_handler to return void
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (14 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 15/39] vl: init main loop earlier Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 17/39] aio: provide platform-independent API Paolo Bonzini
` (23 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
aio.c | 12 +++++-------
qemu-aio.h | 10 +++++-----
2 file modificati, 10 inserzioni(+), 12 rimozioni(-)
diff --git a/aio.c b/aio.c
index c738a4e..e062aab 100644
--- a/aio.c
+++ b/aio.c
@@ -53,11 +53,11 @@ static AioHandler *find_aio_handler(int fd)
return NULL;
}
-int qemu_aio_set_fd_handler(int fd,
- IOHandler *io_read,
- IOHandler *io_write,
- AioFlushHandler *io_flush,
- void *opaque)
+void qemu_aio_set_fd_handler(int fd,
+ IOHandler *io_read,
+ IOHandler *io_write,
+ AioFlushHandler *io_flush,
+ void *opaque)
{
AioHandler *node;
@@ -93,8 +93,6 @@ int qemu_aio_set_fd_handler(int fd,
}
qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque);
-
- return 0;
}
void qemu_aio_flush(void)
diff --git a/qemu-aio.h b/qemu-aio.h
index bfdd35f..27a7e21 100644
--- a/qemu-aio.h
+++ b/qemu-aio.h
@@ -60,10 +60,10 @@ bool qemu_aio_wait(void);
* Code that invokes AIO completion functions should rely on this function
* instead of qemu_set_fd_handler[2].
*/
-int qemu_aio_set_fd_handler(int fd,
- IOHandler *io_read,
- IOHandler *io_write,
- AioFlushHandler *io_flush,
- void *opaque);
+void qemu_aio_set_fd_handler(int fd,
+ IOHandler *io_read,
+ IOHandler *io_write,
+ AioFlushHandler *io_flush,
+ void *opaque);
#endif
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 17/39] aio: provide platform-independent API
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (15 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 16/39] aio: change qemu_aio_set_fd_handler to return void Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 18/39] aio: introduce AioContext, move bottom halves there Paolo Bonzini
` (22 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
This adds to aio.c a platform-independent API based on EventNotifiers, that
can be used by both POSIX and Win32.
Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
Makefile.objs | 4 ++--
aio.c | 9 +++++++++
qemu-aio.h | 19 ++++++++++++++++++-
3 file modificati, 29 inserzioni(+), 3 rimozioni(-)
diff --git a/Makefile.objs b/Makefile.objs
index 5b39c33..98046fc 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -46,6 +46,8 @@ block-obj-y += nbd.o block.o blockjob.o aio.o aes.o qemu-config.o
block-obj-y += qemu-progress.o qemu-sockets.o uri.o notify.o
block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y)
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
+block-obj-$(CONFIG_POSIX) += event_notifier-posix.o
+block-obj-$(CONFIG_WIN32) += event_notifier-win32.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
block-obj-y += block/
block-obj-y += $(qapi-obj-y) qapi-types.o qapi-visit.o
@@ -94,8 +96,6 @@ common-obj-y += bt-host.o bt-vhci.o
common-obj-y += dma-helpers.o
common-obj-y += acl.o
common-obj-$(CONFIG_POSIX) += compatfd.o
-common-obj-$(CONFIG_POSIX) += event_notifier-posix.o
-common-obj-$(CONFIG_WIN32) += event_notifier-win32.o
common-obj-y += qemu-timer.o qemu-timer-common.o
common-obj-y += qtest.o
common-obj-y += vl.o
diff --git a/aio.c b/aio.c
index e062aab..44214e1 100644
--- a/aio.c
+++ b/aio.c
@@ -95,6 +95,15 @@ void qemu_aio_set_fd_handler(int fd,
qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque);
}
+void qemu_aio_set_event_notifier(EventNotifier *notifier,
+ EventNotifierHandler *io_read,
+ AioFlushEventNotifierHandler *io_flush)
+{
+ qemu_aio_set_fd_handler(event_notifier_get_fd(notifier),
+ (IOHandler *)io_read, NULL,
+ (AioFlushHandler *)io_flush, notifier);
+}
+
void qemu_aio_flush(void)
{
while (qemu_aio_wait());
diff --git a/qemu-aio.h b/qemu-aio.h
index 27a7e21..dc416a5 100644
--- a/qemu-aio.h
+++ b/qemu-aio.h
@@ -16,6 +16,7 @@
#include "qemu-common.h"
#include "qemu-char.h"
+#include "event_notifier.h"
typedef struct BlockDriverAIOCB BlockDriverAIOCB;
typedef void BlockDriverCompletionFunc(void *opaque, int ret);
@@ -39,7 +40,7 @@ void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
void qemu_aio_release(void *p);
/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */
-typedef int (AioFlushHandler)(void *opaque);
+typedef int (AioFlushEventNotifierHandler)(EventNotifier *e);
/* Flush any pending AIO operation. This function will block until all
* outstanding AIO operations have been completed or cancelled. */
@@ -53,6 +54,10 @@ void qemu_aio_flush(void);
* Return whether there is still any pending AIO operation. */
bool qemu_aio_wait(void);
+#ifdef CONFIG_POSIX
+/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */
+typedef int (AioFlushHandler)(void *opaque);
+
/* Register a file descriptor and associated callbacks. Behaves very similarly
* to qemu_set_fd_handler2. Unlike qemu_set_fd_handler2, these callbacks will
* be invoked when using either qemu_aio_wait() or qemu_aio_flush().
@@ -65,5 +70,17 @@ void qemu_aio_set_fd_handler(int fd,
IOHandler *io_write,
AioFlushHandler *io_flush,
void *opaque);
+#endif
+
+/* Register an event notifier and associated callbacks. Behaves very similarly
+ * to event_notifier_set_handler. Unlike event_notifier_set_handler, these callbacks
+ * will be invoked when using either qemu_aio_wait() or qemu_aio_flush().
+ *
+ * Code that invokes AIO completion functions should rely on this function
+ * instead of event_notifier_set_handler.
+ */
+void qemu_aio_set_event_notifier(EventNotifier *notifier,
+ EventNotifierHandler *io_read,
+ AioFlushEventNotifierHandler *io_flush);
#endif
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 18/39] aio: introduce AioContext, move bottom halves there
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (16 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 17/39] aio: provide platform-independent API Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 19/39] aio: add I/O handlers to the AioContext interface Paolo Bonzini
` (21 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Start introducing AioContext, which will let us remove globals from
aio.c/async.c, and introduce multiple I/O threads.
The bottom half functions now take an additional AioContext argument.
A bottom half is created with a specific AioContext that remains the
same throughout the lifetime. qemu_bh_new is just a wrapper that
uses a global context.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
aio.c | 2 --
async.c | 30 +++++++++----------
hw/hw.h | 1 +
iohandler.c | 1 +
linux-aio.c | 1 +
main-loop.c | 18 +++++++++++-
main-loop.h | 55 ++---------------------------------
qemu-aio.h | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++-
qemu-char.h | 1 +
qemu-common.h | 1 +
qemu-coroutine-lock.c | 2 +-
11 file modificati, 119 inserzioni(+), 72 rimozioni(-)
diff --git a/aio.c b/aio.c
index 44214e1..7e3fe70 100644
--- a/aio.c
+++ b/aio.c
@@ -18,8 +18,6 @@
#include "qemu-queue.h"
#include "qemu_socket.h"
-typedef struct AioHandler AioHandler;
-
/* The list of registered AIO handlers */
static QLIST_HEAD(, AioHandler) aio_handlers;
diff --git a/async.c b/async.c
index 85cc641..189ee1b 100644
--- a/async.c
+++ b/async.c
@@ -26,9 +26,6 @@
#include "qemu-aio.h"
#include "main-loop.h"
-/* Anchor of the list of Bottom Halves belonging to the context */
-static struct QEMUBH *first_bh;
-
/***********************************************************/
/* bottom halves (can be seen as timers which expire ASAP) */
@@ -41,27 +38,26 @@ struct QEMUBH {
bool deleted;
};
-QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
+QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
{
QEMUBH *bh;
bh = g_malloc0(sizeof(QEMUBH));
bh->cb = cb;
bh->opaque = opaque;
- bh->next = first_bh;
- first_bh = bh;
+ bh->next = ctx->first_bh;
+ ctx->first_bh = bh;
return bh;
}
-int qemu_bh_poll(void)
+int aio_bh_poll(AioContext *ctx)
{
QEMUBH *bh, **bhp, *next;
int ret;
- static int nesting = 0;
- nesting++;
+ ctx->walking_bh++;
ret = 0;
- for (bh = first_bh; bh; bh = next) {
+ for (bh = ctx->first_bh; bh; bh = next) {
next = bh->next;
if (!bh->deleted && bh->scheduled) {
bh->scheduled = 0;
@@ -72,11 +68,11 @@ int qemu_bh_poll(void)
}
}
- nesting--;
+ ctx->walking_bh--;
/* remove deleted bhs */
- if (!nesting) {
- bhp = &first_bh;
+ if (!ctx->walking_bh) {
+ bhp = &ctx->first_bh;
while (*bhp) {
bh = *bhp;
if (bh->deleted) {
@@ -120,11 +116,11 @@ void qemu_bh_delete(QEMUBH *bh)
bh->deleted = 1;
}
-void qemu_bh_update_timeout(uint32_t *timeout)
+void aio_bh_update_timeout(AioContext *ctx, uint32_t *timeout)
{
QEMUBH *bh;
- for (bh = first_bh; bh; bh = bh->next) {
+ for (bh = ctx->first_bh; bh; bh = bh->next) {
if (!bh->deleted && bh->scheduled) {
if (bh->idle) {
/* idle bottom halves will be polled at least
@@ -140,3 +136,7 @@ void qemu_bh_update_timeout(uint32_t *timeout)
}
}
+AioContext *aio_context_new(void)
+{
+ return g_new0(AioContext, 1);
+}
diff --git a/hw/hw.h b/hw/hw.h
index b337ee3..f530f6f 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -10,6 +10,7 @@
#include "ioport.h"
#include "irq.h"
+#include "qemu-aio.h"
#include "qemu-file.h"
#include "vmstate.h"
#include "qemu-log.h"
diff --git a/iohandler.c b/iohandler.c
index a2d871b..60460a6 100644
--- a/iohandler.c
+++ b/iohandler.c
@@ -26,6 +26,7 @@
#include "qemu-common.h"
#include "qemu-char.h"
#include "qemu-queue.h"
+#include "qemu-aio.h"
#include "main-loop.h"
#ifndef _WIN32
diff --git a/linux-aio.c b/linux-aio.c
index ce9b5d4..f3d8ef3 100644
--- a/linux-aio.c
+++ b/linux-aio.c
@@ -9,6 +9,7 @@
*/
#include "qemu-common.h"
#include "qemu-aio.h"
+#include "qemu-queue.h"
#include "block/raw-posix-aio.h"
#include <sys/eventfd.h>
diff --git a/main-loop.c b/main-loop.c
index baefe41..40fdbd3 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -26,6 +26,7 @@
#include "qemu-timer.h"
#include "slirp/slirp.h"
#include "main-loop.h"
+#include "qemu-aio.h"
#ifndef _WIN32
@@ -199,6 +200,8 @@ static int qemu_signal_init(void)
}
#endif
+static AioContext *qemu_aio_context;
+
int qemu_init_main_loop(void)
{
int ret;
@@ -218,6 +221,7 @@ int qemu_init_main_loop(void)
return ret;
}
+ qemu_aio_context = aio_context_new();
return 0;
}
@@ -481,7 +485,7 @@ int main_loop_wait(int nonblocking)
if (nonblocking) {
timeout = 0;
} else {
- qemu_bh_update_timeout(&timeout);
+ aio_bh_update_timeout(qemu_aio_context, &timeout);
}
/* poll any events */
@@ -510,3 +514,15 @@ int main_loop_wait(int nonblocking)
return ret;
}
+
+/* Functions to operate on the main QEMU AioContext. */
+
+QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
+{
+ return aio_bh_new(qemu_aio_context, cb, opaque);
+}
+
+int qemu_bh_poll(void)
+{
+ return aio_bh_poll(qemu_aio_context);
+}
diff --git a/main-loop.h b/main-loop.h
index 91a0aff..1d1a56b 100644
--- a/main-loop.h
+++ b/main-loop.h
@@ -25,6 +25,8 @@
#ifndef QEMU_MAIN_LOOP_H
#define QEMU_MAIN_LOOP_H 1
+#include "qemu-aio.h"
+
#define SIG_IPI SIGUSR1
/**
@@ -163,7 +165,6 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
typedef int IOCanReadHandler(void *opaque);
-typedef void IOHandler(void *opaque);
/**
* qemu_set_fd_handler2: Register a file descriptor with the main loop
@@ -244,56 +245,6 @@ int qemu_set_fd_handler(int fd,
IOHandler *fd_write,
void *opaque);
-typedef struct QEMUBH QEMUBH;
-typedef void QEMUBHFunc(void *opaque);
-
-/**
- * qemu_bh_new: Allocate a new bottom half structure.
- *
- * Bottom halves are lightweight callbacks whose invocation is guaranteed
- * to be wait-free, thread-safe and signal-safe. The #QEMUBH structure
- * is opaque and must be allocated prior to its use.
- */
-QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
-
-/**
- * qemu_bh_schedule: Schedule a bottom half.
- *
- * Scheduling a bottom half interrupts the main loop and causes the
- * execution of the callback that was passed to qemu_bh_new.
- *
- * Bottom halves that are scheduled from a bottom half handler are instantly
- * invoked. This can create an infinite loop if a bottom half handler
- * schedules itself.
- *
- * @bh: The bottom half to be scheduled.
- */
-void qemu_bh_schedule(QEMUBH *bh);
-
-/**
- * qemu_bh_cancel: Cancel execution of a bottom half.
- *
- * Canceling execution of a bottom half undoes the effect of calls to
- * qemu_bh_schedule without freeing its resources yet. While cancellation
- * itself is also wait-free and thread-safe, it can of course race with the
- * loop that executes bottom halves unless you are holding the iothread
- * mutex. This makes it mostly useless if you are not holding the mutex.
- *
- * @bh: The bottom half to be canceled.
- */
-void qemu_bh_cancel(QEMUBH *bh);
-
-/**
- *qemu_bh_delete: Cancel execution of a bottom half and free its resources.
- *
- * Deleting a bottom half frees the memory that was allocated for it by
- * qemu_bh_new. It also implies canceling the bottom half if it was
- * scheduled.
- *
- * @bh: The bottom half to be deleted.
- */
-void qemu_bh_delete(QEMUBH *bh);
-
#ifdef CONFIG_POSIX
/**
* qemu_add_child_watch: Register a child process for reaping.
@@ -349,8 +300,8 @@ void qemu_fd_register(int fd);
void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds);
void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int rc);
+QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
void qemu_bh_schedule_idle(QEMUBH *bh);
int qemu_bh_poll(void);
-void qemu_bh_update_timeout(uint32_t *timeout);
#endif
diff --git a/qemu-aio.h b/qemu-aio.h
index dc416a5..2ed6ad3 100644
--- a/qemu-aio.h
+++ b/qemu-aio.h
@@ -15,7 +15,6 @@
#define QEMU_AIO_H
#include "qemu-common.h"
-#include "qemu-char.h"
#include "event_notifier.h"
typedef struct BlockDriverAIOCB BlockDriverAIOCB;
@@ -39,9 +38,87 @@ void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque);
void qemu_aio_release(void *p);
+typedef struct AioHandler AioHandler;
+typedef void QEMUBHFunc(void *opaque);
+typedef void IOHandler(void *opaque);
+
+typedef struct AioContext {
+ /* Anchor of the list of Bottom Halves belonging to the context */
+ struct QEMUBH *first_bh;
+
+ /* A simple lock used to protect the first_bh list, and ensure that
+ * no callbacks are removed while we're walking and dispatching callbacks.
+ */
+ int walking_bh;
+} AioContext;
+
/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */
typedef int (AioFlushEventNotifierHandler)(EventNotifier *e);
+/**
+ * aio_context_new: Allocate a new AioContext.
+ *
+ * AioContext provide a mini event-loop that can be waited on synchronously.
+ * They also provide bottom halves, a service to execute a piece of code
+ * as soon as possible.
+ */
+AioContext *aio_context_new(void);
+
+/**
+ * aio_bh_new: Allocate a new bottom half structure.
+ *
+ * Bottom halves are lightweight callbacks whose invocation is guaranteed
+ * to be wait-free, thread-safe and signal-safe. The #QEMUBH structure
+ * is opaque and must be allocated prior to its use.
+ */
+QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque);
+
+/**
+ * aio_bh_poll: Poll bottom halves for an AioContext.
+ *
+ * These are internal functions used by the QEMU main loop.
+ */
+int aio_bh_poll(AioContext *ctx);
+void aio_bh_update_timeout(AioContext *ctx, uint32_t *timeout);
+
+/**
+ * qemu_bh_schedule: Schedule a bottom half.
+ *
+ * Scheduling a bottom half interrupts the main loop and causes the
+ * execution of the callback that was passed to qemu_bh_new.
+ *
+ * Bottom halves that are scheduled from a bottom half handler are instantly
+ * invoked. This can create an infinite loop if a bottom half handler
+ * schedules itself.
+ *
+ * @bh: The bottom half to be scheduled.
+ */
+void qemu_bh_schedule(QEMUBH *bh);
+
+/**
+ * qemu_bh_cancel: Cancel execution of a bottom half.
+ *
+ * Canceling execution of a bottom half undoes the effect of calls to
+ * qemu_bh_schedule without freeing its resources yet. While cancellation
+ * itself is also wait-free and thread-safe, it can of course race with the
+ * loop that executes bottom halves unless you are holding the iothread
+ * mutex. This makes it mostly useless if you are not holding the mutex.
+ *
+ * @bh: The bottom half to be canceled.
+ */
+void qemu_bh_cancel(QEMUBH *bh);
+
+/**
+ *qemu_bh_delete: Cancel execution of a bottom half and free its resources.
+ *
+ * Deleting a bottom half frees the memory that was allocated for it by
+ * qemu_bh_new. It also implies canceling the bottom half if it was
+ * scheduled.
+ *
+ * @bh: The bottom half to be deleted.
+ */
+void qemu_bh_delete(QEMUBH *bh);
+
/* Flush any pending AIO operation. This function will block until all
* outstanding AIO operations have been completed or cancelled. */
void qemu_aio_flush(void);
diff --git a/qemu-char.h b/qemu-char.h
index 486644b..5087168 100644
--- a/qemu-char.h
+++ b/qemu-char.h
@@ -5,6 +5,7 @@
#include "qemu-queue.h"
#include "qemu-option.h"
#include "qemu-config.h"
+#include "qemu-aio.h"
#include "qobject.h"
#include "qstring.h"
#include "main-loop.h"
diff --git a/qemu-common.h b/qemu-common.h
index 36ce522..24e13cc 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -14,6 +14,7 @@
typedef struct QEMUTimer QEMUTimer;
typedef struct QEMUFile QEMUFile;
+typedef struct QEMUBH QEMUBH;
typedef struct DeviceState DeviceState;
struct Monitor;
diff --git a/qemu-coroutine-lock.c b/qemu-coroutine-lock.c
index 26ad76b..9dda3f8 100644
--- a/qemu-coroutine-lock.c
+++ b/qemu-coroutine-lock.c
@@ -26,7 +26,7 @@
#include "qemu-coroutine.h"
#include "qemu-coroutine-int.h"
#include "qemu-queue.h"
-#include "main-loop.h"
+#include "qemu-aio.h"
#include "trace.h"
static QTAILQ_HEAD(, Coroutine) unlock_bh_queue =
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 19/39] aio: add I/O handlers to the AioContext interface
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (17 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 18/39] aio: introduce AioContext, move bottom halves there Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 20/39] aio: test node->deleted before calling io_flush Paolo Bonzini
` (20 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
With this patch, I/O handlers (including event notifier handlers) can be
attached to a single AioContext.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
aio.c | 68 ++++++++++++++++++++++++-------------------------------------
async.c | 6 ++++++
main-loop.c | 33 ++++++++++++++++++++++++++++++
qemu-aio.h | 42 +++++++++++++++++++++++++++++++-------
4 file modificati, 101 inserzioni(+), 48 rimozioni(-)
diff --git a/aio.c b/aio.c
index 7e3fe70..c89f1e9 100644
--- a/aio.c
+++ b/aio.c
@@ -18,15 +18,6 @@
#include "qemu-queue.h"
#include "qemu_socket.h"
-/* The list of registered AIO handlers */
-static QLIST_HEAD(, AioHandler) aio_handlers;
-
-/* This is a simple lock used to protect the aio_handlers list. Specifically,
- * it's used to ensure that no callbacks are removed while we're walking and
- * dispatching callbacks.
- */
-static int walking_handlers;
-
struct AioHandler
{
int fd;
@@ -38,11 +29,11 @@ struct AioHandler
QLIST_ENTRY(AioHandler) node;
};
-static AioHandler *find_aio_handler(int fd)
+static AioHandler *find_aio_handler(AioContext *ctx, int fd)
{
AioHandler *node;
- QLIST_FOREACH(node, &aio_handlers, node) {
+ QLIST_FOREACH(node, &ctx->aio_handlers, node) {
if (node->fd == fd)
if (!node->deleted)
return node;
@@ -51,21 +42,22 @@ static AioHandler *find_aio_handler(int fd)
return NULL;
}
-void qemu_aio_set_fd_handler(int fd,
- IOHandler *io_read,
- IOHandler *io_write,
- AioFlushHandler *io_flush,
- void *opaque)
+void aio_set_fd_handler(AioContext *ctx,
+ int fd,
+ IOHandler *io_read,
+ IOHandler *io_write,
+ AioFlushHandler *io_flush,
+ void *opaque)
{
AioHandler *node;
- node = find_aio_handler(fd);
+ node = find_aio_handler(ctx, fd);
/* Are we deleting the fd handler? */
if (!io_read && !io_write) {
if (node) {
/* If the lock is held, just mark the node as deleted */
- if (walking_handlers)
+ if (ctx->walking_handlers)
node->deleted = 1;
else {
/* Otherwise, delete it for real. We can't just mark it as
@@ -81,7 +73,7 @@ void qemu_aio_set_fd_handler(int fd,
/* Alloc and insert if it's not already there */
node = g_malloc0(sizeof(AioHandler));
node->fd = fd;
- QLIST_INSERT_HEAD(&aio_handlers, node, node);
+ QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node);
}
/* Update handler with latest information */
node->io_read = io_read;
@@ -89,25 +81,19 @@ void qemu_aio_set_fd_handler(int fd,
node->io_flush = io_flush;
node->opaque = opaque;
}
-
- qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque);
-}
-
-void qemu_aio_set_event_notifier(EventNotifier *notifier,
- EventNotifierHandler *io_read,
- AioFlushEventNotifierHandler *io_flush)
-{
- qemu_aio_set_fd_handler(event_notifier_get_fd(notifier),
- (IOHandler *)io_read, NULL,
- (AioFlushHandler *)io_flush, notifier);
}
-void qemu_aio_flush(void)
+void aio_set_event_notifier(AioContext *ctx,
+ EventNotifier *notifier,
+ EventNotifierHandler *io_read,
+ AioFlushEventNotifierHandler *io_flush)
{
- while (qemu_aio_wait());
+ aio_set_fd_handler(ctx, event_notifier_get_fd(notifier),
+ (IOHandler *)io_read, NULL,
+ (AioFlushHandler *)io_flush, notifier);
}
-bool qemu_aio_wait(void)
+bool aio_wait(AioContext *ctx)
{
AioHandler *node;
fd_set rdfds, wrfds;
@@ -120,18 +106,18 @@ bool qemu_aio_wait(void)
* Do not call select in this case, because it is possible that the caller
* does not need a complete flush (as is the case for qemu_aio_wait loops).
*/
- if (qemu_bh_poll()) {
+ if (aio_bh_poll(ctx)) {
return true;
}
- walking_handlers++;
+ ctx->walking_handlers++;
FD_ZERO(&rdfds);
FD_ZERO(&wrfds);
/* fill fd sets */
busy = false;
- QLIST_FOREACH(node, &aio_handlers, node) {
+ QLIST_FOREACH(node, &ctx->aio_handlers, node) {
/* If there aren't pending AIO operations, don't invoke callbacks.
* Otherwise, if there are no AIO requests, qemu_aio_wait() would
* wait indefinitely.
@@ -152,7 +138,7 @@ bool qemu_aio_wait(void)
}
}
- walking_handlers--;
+ ctx->walking_handlers--;
/* No AIO operations? Get us out of here */
if (!busy) {
@@ -166,11 +152,11 @@ bool qemu_aio_wait(void)
if (ret > 0) {
/* we have to walk very carefully in case
* qemu_aio_set_fd_handler is called while we're walking */
- node = QLIST_FIRST(&aio_handlers);
+ node = QLIST_FIRST(&ctx->aio_handlers);
while (node) {
AioHandler *tmp;
- walking_handlers++;
+ ctx->walking_handlers++;
if (!node->deleted &&
FD_ISSET(node->fd, &rdfds) &&
@@ -186,9 +172,9 @@ bool qemu_aio_wait(void)
tmp = node;
node = QLIST_NEXT(node, node);
- walking_handlers--;
+ ctx->walking_handlers--;
- if (!walking_handlers && tmp->deleted) {
+ if (!ctx->walking_handlers && tmp->deleted) {
QLIST_REMOVE(tmp, node);
g_free(tmp);
}
diff --git a/async.c b/async.c
index 189ee1b..c99db79 100644
--- a/async.c
+++ b/async.c
@@ -136,7 +136,13 @@ void aio_bh_update_timeout(AioContext *ctx, uint32_t *timeout)
}
}
+
AioContext *aio_context_new(void)
{
return g_new0(AioContext, 1);
}
+
+void aio_flush(AioContext *ctx)
+{
+ while (aio_wait(ctx));
+}
diff --git a/main-loop.c b/main-loop.c
index 40fdbd3..8f0117e 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -526,3 +526,36 @@ int qemu_bh_poll(void)
{
return aio_bh_poll(qemu_aio_context);
}
+
+void qemu_aio_flush(void)
+{
+ aio_flush(qemu_aio_context);
+}
+
+bool qemu_aio_wait(void)
+{
+ return aio_wait(qemu_aio_context);
+}
+
+void qemu_aio_set_fd_handler(int fd,
+ IOHandler *io_read,
+ IOHandler *io_write,
+ AioFlushHandler *io_flush,
+ void *opaque)
+{
+ aio_set_fd_handler(qemu_aio_context, fd, io_read, io_write, io_flush,
+ opaque);
+
+ qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque);
+}
+
+#ifdef CONFIG_POSIX
+void qemu_aio_set_event_notifier(EventNotifier *notifier,
+ EventNotifierHandler *io_read,
+ AioFlushEventNotifierHandler *io_flush)
+{
+ qemu_aio_set_fd_handler(event_notifier_get_fd(notifier),
+ (IOHandler *)io_read, NULL,
+ (AioFlushHandler *)io_flush, notifier);
+}
+#endif
diff --git a/qemu-aio.h b/qemu-aio.h
index 2ed6ad3..f8a93d8 100644
--- a/qemu-aio.h
+++ b/qemu-aio.h
@@ -15,6 +15,7 @@
#define QEMU_AIO_H
#include "qemu-common.h"
+#include "qemu-queue.h"
#include "event_notifier.h"
typedef struct BlockDriverAIOCB BlockDriverAIOCB;
@@ -43,6 +44,15 @@ typedef void QEMUBHFunc(void *opaque);
typedef void IOHandler(void *opaque);
typedef struct AioContext {
+ /* The list of registered AIO handlers */
+ QLIST_HEAD(, AioHandler) aio_handlers;
+
+ /* This is a simple lock used to protect the aio_handlers list.
+ * Specifically, it's used to ensure that no callbacks are removed while
+ * we're walking and dispatching callbacks.
+ */
+ int walking_handlers;
+
/* Anchor of the list of Bottom Halves belonging to the context */
struct QEMUBH *first_bh;
@@ -121,7 +131,7 @@ void qemu_bh_delete(QEMUBH *bh);
/* Flush any pending AIO operation. This function will block until all
* outstanding AIO operations have been completed or cancelled. */
-void qemu_aio_flush(void);
+void aio_flush(AioContext *ctx);
/* Wait for a single AIO completion to occur. This function will wait
* until a single AIO event has completed and it will ensure something
@@ -129,7 +139,7 @@ void qemu_aio_flush(void);
* result of executing I/O completion or bh callbacks.
*
* Return whether there is still any pending AIO operation. */
-bool qemu_aio_wait(void);
+bool aio_wait(AioContext *ctx);
#ifdef CONFIG_POSIX
/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */
@@ -142,11 +152,12 @@ typedef int (AioFlushHandler)(void *opaque);
* Code that invokes AIO completion functions should rely on this function
* instead of qemu_set_fd_handler[2].
*/
-void qemu_aio_set_fd_handler(int fd,
- IOHandler *io_read,
- IOHandler *io_write,
- AioFlushHandler *io_flush,
- void *opaque);
+void aio_set_fd_handler(AioContext *ctx,
+ int fd,
+ IOHandler *io_read,
+ IOHandler *io_write,
+ AioFlushHandler *io_flush,
+ void *opaque);
#endif
/* Register an event notifier and associated callbacks. Behaves very similarly
@@ -156,8 +167,25 @@ void qemu_aio_set_fd_handler(int fd,
* Code that invokes AIO completion functions should rely on this function
* instead of event_notifier_set_handler.
*/
+void aio_set_event_notifier(AioContext *ctx,
+ EventNotifier *notifier,
+ EventNotifierHandler *io_read,
+ AioFlushEventNotifierHandler *io_flush);
+
+/* Functions to operate on the main QEMU AioContext. */
+
+void qemu_aio_flush(void);
+bool qemu_aio_wait(void);
void qemu_aio_set_event_notifier(EventNotifier *notifier,
EventNotifierHandler *io_read,
AioFlushEventNotifierHandler *io_flush);
+#ifdef CONFIG_POSIX
+void qemu_aio_set_fd_handler(int fd,
+ IOHandler *io_read,
+ IOHandler *io_write,
+ AioFlushHandler *io_flush,
+ void *opaque);
+#endif
+
#endif
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 20/39] aio: test node->deleted before calling io_flush
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (18 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 19/39] aio: add I/O handlers to the AioContext interface Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 21/39] aio: add non-blocking variant of aio_wait Paolo Bonzini
` (19 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Otherwise, there could be a case where io_flush accesses freed
memory because it should not have been called.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
aio.c | 2 +-
1 file modificato, 1 inserzione(+). 1 rimozione(-)
diff --git a/aio.c b/aio.c
index c89f1e9..734d2cf 100644
--- a/aio.c
+++ b/aio.c
@@ -122,7 +122,7 @@ bool aio_wait(AioContext *ctx)
* Otherwise, if there are no AIO requests, qemu_aio_wait() would
* wait indefinitely.
*/
- if (node->io_flush) {
+ if (!node->deleted && node->io_flush) {
if (node->io_flush(node->opaque) == 0) {
continue;
}
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 21/39] aio: add non-blocking variant of aio_wait
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (19 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 20/39] aio: test node->deleted before calling io_flush Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 22/39] aio: prepare for introducing GSource-based dispatch Paolo Bonzini
` (18 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
This will be used when polling the GSource attached to an AioContext.
Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
aio.c | 20 +++++++++++++++-----
async.c | 2 +-
main-loop.c | 2 +-
qemu-aio.h | 21 +++++++++++++++------
4 file modificati, 32 inserzioni(+), 13 rimozioni(-)
diff --git a/aio.c b/aio.c
index 734d2cf..1d5e0c6 100644
--- a/aio.c
+++ b/aio.c
@@ -93,13 +93,16 @@ void aio_set_event_notifier(AioContext *ctx,
(AioFlushHandler *)io_flush, notifier);
}
-bool aio_wait(AioContext *ctx)
+bool aio_poll(AioContext *ctx, bool blocking)
{
+ static struct timeval tv0;
AioHandler *node;
fd_set rdfds, wrfds;
int max_fd = -1;
int ret;
- bool busy;
+ bool busy, progress;
+
+ progress = false;
/*
* If there are callbacks left that have been queued, we need to call then.
@@ -107,6 +110,11 @@ bool aio_wait(AioContext *ctx)
* does not need a complete flush (as is the case for qemu_aio_wait loops).
*/
if (aio_bh_poll(ctx)) {
+ blocking = false;
+ progress = true;
+ }
+
+ if (progress && !blocking) {
return true;
}
@@ -142,11 +150,11 @@ bool aio_wait(AioContext *ctx)
/* No AIO operations? Get us out of here */
if (!busy) {
- return false;
+ return progress;
}
/* wait until next event */
- ret = select(max_fd, &rdfds, &wrfds, NULL, NULL);
+ ret = select(max_fd, &rdfds, &wrfds, NULL, blocking ? NULL : &tv0);
/* if we have any readable fds, dispatch event */
if (ret > 0) {
@@ -161,11 +169,13 @@ bool aio_wait(AioContext *ctx)
if (!node->deleted &&
FD_ISSET(node->fd, &rdfds) &&
node->io_read) {
+ progress = true;
node->io_read(node->opaque);
}
if (!node->deleted &&
FD_ISSET(node->fd, &wrfds) &&
node->io_write) {
+ progress = true;
node->io_write(node->opaque);
}
@@ -181,5 +191,5 @@ bool aio_wait(AioContext *ctx)
}
}
- return true;
+ return progress;
}
diff --git a/async.c b/async.c
index c99db79..513bdd7 100644
--- a/async.c
+++ b/async.c
@@ -144,5 +144,5 @@ AioContext *aio_context_new(void)
void aio_flush(AioContext *ctx)
{
- while (aio_wait(ctx));
+ while (aio_poll(ctx, true));
}
diff --git a/main-loop.c b/main-loop.c
index 8f0117e..1fdc3bd 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -534,7 +534,7 @@ void qemu_aio_flush(void)
bool qemu_aio_wait(void)
{
- return aio_wait(qemu_aio_context);
+ return aio_poll(qemu_aio_context, true);
}
void qemu_aio_set_fd_handler(int fd,
diff --git a/qemu-aio.h b/qemu-aio.h
index f8a93d8..f19201e 100644
--- a/qemu-aio.h
+++ b/qemu-aio.h
@@ -133,13 +133,22 @@ void qemu_bh_delete(QEMUBH *bh);
* outstanding AIO operations have been completed or cancelled. */
void aio_flush(AioContext *ctx);
-/* Wait for a single AIO completion to occur. This function will wait
- * until a single AIO event has completed and it will ensure something
- * has moved before returning. This can issue new pending aio as
- * result of executing I/O completion or bh callbacks.
+/* Progress in completing AIO work to occur. This can issue new pending
+ * aio as a result of executing I/O completion or bh callbacks.
*
- * Return whether there is still any pending AIO operation. */
-bool aio_wait(AioContext *ctx);
+ * If there is no pending AIO operation or completion (bottom half),
+ * return false. If there are pending bottom halves, return true.
+ *
+ * If there are no pending bottom halves, but there are pending AIO
+ * operations, it may not be possible to make any progress without
+ * blocking. If @blocking is true, this function will wait until one
+ * or more AIO events have completed, to ensure something has moved
+ * before returning.
+ *
+ * If @blocking is false, this function will also return false if the
+ * function cannot make any progress without blocking.
+ */
+bool aio_poll(AioContext *ctx, bool blocking);
#ifdef CONFIG_POSIX
/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 22/39] aio: prepare for introducing GSource-based dispatch
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (20 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 21/39] aio: add non-blocking variant of aio_wait Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 23/39] aio: add Win32 implementation Paolo Bonzini
` (17 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
This adds a GPollFD to each AioHandler. It will then be possible to
attach these GPollFDs to a GSource, and from there to the main loop.
aio_wait examines the GPollFDs and avoids calling select() if any
is set (similar to what it does if bottom halves are available).
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
aio.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++---------
qemu-aio.h | 7 +++++
2 file modificati, 87 inserzioni(+), 13 rimozioni(-)
diff --git a/aio.c b/aio.c
index 1d5e0c6..4424722 100644
--- a/aio.c
+++ b/aio.c
@@ -20,7 +20,7 @@
struct AioHandler
{
- int fd;
+ GPollFD pfd;
IOHandler *io_read;
IOHandler *io_write;
AioFlushHandler *io_flush;
@@ -34,7 +34,7 @@ static AioHandler *find_aio_handler(AioContext *ctx, int fd)
AioHandler *node;
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
- if (node->fd == fd)
+ if (node->pfd.fd == fd)
if (!node->deleted)
return node;
}
@@ -57,9 +57,10 @@ void aio_set_fd_handler(AioContext *ctx,
if (!io_read && !io_write) {
if (node) {
/* If the lock is held, just mark the node as deleted */
- if (ctx->walking_handlers)
+ if (ctx->walking_handlers) {
node->deleted = 1;
- else {
+ node->pfd.revents = 0;
+ } else {
/* Otherwise, delete it for real. We can't just mark it as
* deleted because deleted nodes are only cleaned up after
* releasing the walking_handlers lock.
@@ -72,7 +73,7 @@ void aio_set_fd_handler(AioContext *ctx,
if (node == NULL) {
/* Alloc and insert if it's not already there */
node = g_malloc0(sizeof(AioHandler));
- node->fd = fd;
+ node->pfd.fd = fd;
QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node);
}
/* Update handler with latest information */
@@ -80,6 +81,9 @@ void aio_set_fd_handler(AioContext *ctx,
node->io_write = io_write;
node->io_flush = io_flush;
node->opaque = opaque;
+
+ node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP : 0);
+ node->pfd.events |= (io_write ? G_IO_OUT : 0);
}
}
@@ -93,6 +97,32 @@ void aio_set_event_notifier(AioContext *ctx,
(AioFlushHandler *)io_flush, notifier);
}
+bool aio_pending(AioContext *ctx)
+{
+ AioHandler *node;
+
+ QLIST_FOREACH(node, &ctx->aio_handlers, node) {
+ int revents;
+
+ /*
+ * FIXME: right now we cannot get G_IO_HUP and G_IO_ERR because
+ * main-loop.c is still select based (due to the slirp legacy).
+ * If main-loop.c ever switches to poll, G_IO_ERR should be
+ * tested too. Dispatching G_IO_ERR to both handlers should be
+ * okay, since handlers need to be ready for spurious wakeups.
+ */
+ revents = node->pfd.revents & node->pfd.events;
+ if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) {
+ return true;
+ }
+ if (revents & (G_IO_OUT | G_IO_ERR) && node->io_write) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool aio_poll(AioContext *ctx, bool blocking)
{
static struct timeval tv0;
@@ -114,6 +144,43 @@ bool aio_poll(AioContext *ctx, bool blocking)
progress = true;
}
+ /*
+ * Then dispatch any pending callbacks from the GSource.
+ *
+ * We have to walk very carefully in case qemu_aio_set_fd_handler is
+ * called while we're walking.
+ */
+ node = QLIST_FIRST(&ctx->aio_handlers);
+ while (node) {
+ AioHandler *tmp;
+ int revents;
+
+ ctx->walking_handlers++;
+
+ revents = node->pfd.revents & node->pfd.events;
+ node->pfd.revents = 0;
+
+ /* See comment in aio_pending. */
+ if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) {
+ node->io_read(node->opaque);
+ progress = true;
+ }
+ if (revents & (G_IO_OUT | G_IO_ERR) && node->io_write) {
+ node->io_write(node->opaque);
+ progress = true;
+ }
+
+ tmp = node;
+ node = QLIST_NEXT(node, node);
+
+ ctx->walking_handlers--;
+
+ if (!ctx->walking_handlers && tmp->deleted) {
+ QLIST_REMOVE(tmp, node);
+ g_free(tmp);
+ }
+ }
+
if (progress && !blocking) {
return true;
}
@@ -137,12 +204,12 @@ bool aio_poll(AioContext *ctx, bool blocking)
busy = true;
}
if (!node->deleted && node->io_read) {
- FD_SET(node->fd, &rdfds);
- max_fd = MAX(max_fd, node->fd + 1);
+ FD_SET(node->pfd.fd, &rdfds);
+ max_fd = MAX(max_fd, node->pfd.fd + 1);
}
if (!node->deleted && node->io_write) {
- FD_SET(node->fd, &wrfds);
- max_fd = MAX(max_fd, node->fd + 1);
+ FD_SET(node->pfd.fd, &wrfds);
+ max_fd = MAX(max_fd, node->pfd.fd + 1);
}
}
@@ -167,16 +234,16 @@ bool aio_poll(AioContext *ctx, bool blocking)
ctx->walking_handlers++;
if (!node->deleted &&
- FD_ISSET(node->fd, &rdfds) &&
+ FD_ISSET(node->pfd.fd, &rdfds) &&
node->io_read) {
- progress = true;
node->io_read(node->opaque);
+ progress = true;
}
if (!node->deleted &&
- FD_ISSET(node->fd, &wrfds) &&
+ FD_ISSET(node->pfd.fd, &wrfds) &&
node->io_write) {
- progress = true;
node->io_write(node->opaque);
+ progress = true;
}
tmp = node;
diff --git a/qemu-aio.h b/qemu-aio.h
index f19201e..ac24896 100644
--- a/qemu-aio.h
+++ b/qemu-aio.h
@@ -133,6 +133,13 @@ void qemu_bh_delete(QEMUBH *bh);
* outstanding AIO operations have been completed or cancelled. */
void aio_flush(AioContext *ctx);
+/* Return whether there are any pending callbacks from the GSource
+ * attached to the AioContext.
+ *
+ * This is used internally in the implementation of the GSource.
+ */
+bool aio_pending(AioContext *ctx);
+
/* Progress in completing AIO work to occur. This can issue new pending
* aio as a result of executing I/O completion or bh callbacks.
*
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 23/39] aio: add Win32 implementation
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (21 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 22/39] aio: prepare for introducing GSource-based dispatch Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 24/39] aio: make AioContexts GSources Paolo Bonzini
` (16 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
The Win32 implementation will only accept EventNotifiers, thus a few
drivers are disabled under Windows. EventNotifiers are a good match
for the GSource implementation, too, because the Win32 port of glib
allows to place their HANDLEs in a GPollFD.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
Makefile.objs | 6 +-
aio.c => aio-posix.c | 0
aio-win32.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++++++
block/Makefile.objs | 6 +-
main-loop.c | 2 +-
5 file modificati, 218 inserzioni(+), 5 rimozioni(-)
rename aio.c => aio-posix.c (100%)
create mode 100644 aio-win32.c
diff --git a/Makefile.objs b/Makefile.objs
index 98046fc..a8ade04 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -42,12 +42,12 @@ coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o
# block-obj-y is code used by both qemu system emulation and qemu-img
block-obj-y = iov.o cache-utils.o qemu-option.o module.o async.o
-block-obj-y += nbd.o block.o blockjob.o aio.o aes.o qemu-config.o
+block-obj-y += nbd.o block.o blockjob.o aes.o qemu-config.o
block-obj-y += qemu-progress.o qemu-sockets.o uri.o notify.o
block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y)
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
-block-obj-$(CONFIG_POSIX) += event_notifier-posix.o
-block-obj-$(CONFIG_WIN32) += event_notifier-win32.o
+block-obj-$(CONFIG_POSIX) += event_notifier-posix.o aio-posix.o
+block-obj-$(CONFIG_WIN32) += event_notifier-win32.o aio-win32.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
block-obj-y += block/
block-obj-y += $(qapi-obj-y) qapi-types.o qapi-visit.o
diff --git a/aio.c b/aio-posix.c
similarity index 100%
rename from aio.c
rename to aio-posix.c
diff --git a/aio-win32.c b/aio-win32.c
new file mode 100644
index 0000000..9881fdb
--- /dev/null
+++ b/aio-win32.c
@@ -0,0 +1,209 @@
+/*
+ * QEMU aio implementation
+ *
+ * Copyright IBM Corp., 2008
+ * Copyright Red Hat Inc., 2012
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu-common.h"
+#include "block.h"
+#include "qemu-queue.h"
+#include "qemu_socket.h"
+
+struct AioHandler {
+ EventNotifier *e;
+ EventNotifierHandler *io_notify;
+ AioFlushEventNotifierHandler *io_flush;
+ GPollFD pfd;
+ int deleted;
+ QLIST_ENTRY(AioHandler) node;
+};
+
+void aio_set_event_notifier(AioContext *ctx,
+ EventNotifier *e,
+ EventNotifierHandler *io_notify,
+ AioFlushEventNotifierHandler *io_flush)
+{
+ AioHandler *node;
+
+ QLIST_FOREACH(node, &ctx->aio_handlers, node) {
+ if (node->e == e && !node->deleted) {
+ break;
+ }
+ }
+
+ /* Are we deleting the fd handler? */
+ if (!io_notify) {
+ if (node) {
+ /* If the lock is held, just mark the node as deleted */
+ if (ctx->walking_handlers) {
+ node->deleted = 1;
+ node->pfd.revents = 0;
+ } else {
+ /* Otherwise, delete it for real. We can't just mark it as
+ * deleted because deleted nodes are only cleaned up after
+ * releasing the walking_handlers lock.
+ */
+ QLIST_REMOVE(node, node);
+ g_free(node);
+ }
+ }
+ } else {
+ if (node == NULL) {
+ /* Alloc and insert if it's not already there */
+ node = g_malloc0(sizeof(AioHandler));
+ node->e = e;
+ node->pfd.fd = (uintptr_t)event_notifier_get_handle(e);
+ node->pfd.events = G_IO_IN;
+ QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node);
+ }
+ /* Update handler with latest information */
+ node->io_notify = io_notify;
+ node->io_flush = io_flush;
+ }
+}
+
+bool aio_pending(AioContext *ctx)
+{
+ AioHandler *node;
+
+ QLIST_FOREACH(node, &ctx->aio_handlers, node) {
+ if (node->pfd.revents && node->io_notify) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool aio_poll(AioContext *ctx, bool blocking)
+{
+ AioHandler *node;
+ HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
+ bool busy, progress;
+ int count;
+
+ progress = false;
+
+ /*
+ * If there are callbacks left that have been queued, we need to call then.
+ * Do not call select in this case, because it is possible that the caller
+ * does not need a complete flush (as is the case for qemu_aio_wait loops).
+ */
+ if (aio_bh_poll(ctx)) {
+ blocking = false;
+ progress = true;
+ }
+
+ /*
+ * Then dispatch any pending callbacks from the GSource.
+ *
+ * We have to walk very carefully in case qemu_aio_set_fd_handler is
+ * called while we're walking.
+ */
+ node = QLIST_FIRST(&ctx->aio_handlers);
+ while (node) {
+ AioHandler *tmp;
+
+ ctx->walking_handlers++;
+
+ if (node->pfd.revents && node->io_notify) {
+ node->pfd.revents = 0;
+ node->io_notify(node->e);
+ progress = true;
+ }
+
+ tmp = node;
+ node = QLIST_NEXT(node, node);
+
+ ctx->walking_handlers--;
+
+ if (!ctx->walking_handlers && tmp->deleted) {
+ QLIST_REMOVE(tmp, node);
+ g_free(tmp);
+ }
+ }
+
+ if (progress && !blocking) {
+ return true;
+ }
+
+ ctx->walking_handlers++;
+
+ /* fill fd sets */
+ busy = false;
+ count = 0;
+ QLIST_FOREACH(node, &ctx->aio_handlers, node) {
+ /* If there aren't pending AIO operations, don't invoke callbacks.
+ * Otherwise, if there are no AIO requests, qemu_aio_wait() would
+ * wait indefinitely.
+ */
+ if (!node->deleted && node->io_flush) {
+ if (node->io_flush(node->e) == 0) {
+ continue;
+ }
+ busy = true;
+ }
+ if (!node->deleted && node->io_notify) {
+ events[count++] = event_notifier_get_handle(node->e);
+ }
+ }
+
+ ctx->walking_handlers--;
+
+ /* No AIO operations? Get us out of here */
+ if (!busy) {
+ return progress;
+ }
+
+ /* wait until next event */
+ for (;;) {
+ int timeout = blocking ? INFINITE : 0;
+ int ret = WaitForMultipleObjects(count, events, FALSE, timeout);
+
+ /* if we have any signaled events, dispatch event */
+ if ((DWORD) (ret - WAIT_OBJECT_0) >= count) {
+ break;
+ }
+
+ blocking = false;
+
+ /* we have to walk very carefully in case
+ * qemu_aio_set_fd_handler is called while we're walking */
+ node = QLIST_FIRST(&ctx->aio_handlers);
+ while (node) {
+ AioHandler *tmp;
+
+ ctx->walking_handlers++;
+
+ if (!node->deleted &&
+ event_notifier_get_handle(node->e) == events[ret - WAIT_OBJECT_0] &&
+ node->io_notify) {
+ node->io_notify(node->e);
+ progress = true;
+ }
+
+ tmp = node;
+ node = QLIST_NEXT(node, node);
+
+ ctx->walking_handlers--;
+
+ if (!ctx->walking_handlers && tmp->deleted) {
+ QLIST_REMOVE(tmp, node);
+ g_free(tmp);
+ }
+ }
+ }
+
+ return progress;
+}
diff --git a/block/Makefile.objs b/block/Makefile.objs
index 554f429..684765b 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -2,13 +2,17 @@ block-obj-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat
block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
block-obj-y += qed-check.o
-block-obj-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
+block-obj-y += parallels.o blkdebug.o blkverify.o
block-obj-$(CONFIG_WIN32) += raw-win32.o
block-obj-$(CONFIG_POSIX) += raw-posix.o
+
+ifeq ($(CONFIG_POSIX),y)
+block-obj-y += nbd.o sheepdog.o
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
block-obj-$(CONFIG_CURL) += curl.o
block-obj-$(CONFIG_RBD) += rbd.o
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
+endif
common-obj-y += stream.o
common-obj-y += commit.o
diff --git a/main-loop.c b/main-loop.c
index 1fdc3bd..a86c275 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -537,6 +537,7 @@ bool qemu_aio_wait(void)
return aio_poll(qemu_aio_context, true);
}
+#ifdef CONFIG_POSIX
void qemu_aio_set_fd_handler(int fd,
IOHandler *io_read,
IOHandler *io_write,
@@ -549,7 +550,6 @@ void qemu_aio_set_fd_handler(int fd,
qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque);
}
-#ifdef CONFIG_POSIX
void qemu_aio_set_event_notifier(EventNotifier *notifier,
EventNotifierHandler *io_read,
AioFlushEventNotifierHandler *io_flush)
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 24/39] aio: make AioContexts GSources
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (22 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 23/39] aio: add Win32 implementation Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 25/39] aio: add aio_notify Paolo Bonzini
` (15 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
This lets AioContexts be used (optionally) with a glib main loop.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
aio-posix.c | 4 ++++
aio-win32.c | 4 ++++
async.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
qemu-aio.h | 23 ++++++++++++++++++++++
4 file modificati, 95 inserzioni(+). 1 rimozione(-)
diff --git a/aio-posix.c b/aio-posix.c
index 4424722..65b2607 100644
--- a/aio-posix.c
+++ b/aio-posix.c
@@ -56,6 +56,8 @@ void aio_set_fd_handler(AioContext *ctx,
/* Are we deleting the fd handler? */
if (!io_read && !io_write) {
if (node) {
+ g_source_remove_poll(&ctx->source, &node->pfd);
+
/* If the lock is held, just mark the node as deleted */
if (ctx->walking_handlers) {
node->deleted = 1;
@@ -75,6 +77,8 @@ void aio_set_fd_handler(AioContext *ctx,
node = g_malloc0(sizeof(AioHandler));
node->pfd.fd = fd;
QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node);
+
+ g_source_add_poll(&ctx->source, &node->pfd);
}
/* Update handler with latest information */
node->io_read = io_read;
diff --git a/aio-win32.c b/aio-win32.c
index 9881fdb..e460bd8 100644
--- a/aio-win32.c
+++ b/aio-win32.c
@@ -45,6 +45,8 @@ void aio_set_event_notifier(AioContext *ctx,
/* Are we deleting the fd handler? */
if (!io_notify) {
if (node) {
+ g_source_remove_poll(&ctx->source, &node->pfd);
+
/* If the lock is held, just mark the node as deleted */
if (ctx->walking_handlers) {
node->deleted = 1;
@@ -66,6 +68,8 @@ void aio_set_event_notifier(AioContext *ctx,
node->pfd.fd = (uintptr_t)event_notifier_get_handle(e);
node->pfd.events = G_IO_IN;
QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node);
+
+ g_source_add_poll(&ctx->source, &node->pfd);
}
/* Update handler with latest information */
node->io_notify = io_notify;
diff --git a/async.c b/async.c
index 513bdd7..4ffdd98 100644
--- a/async.c
+++ b/async.c
@@ -136,10 +136,73 @@ void aio_bh_update_timeout(AioContext *ctx, uint32_t *timeout)
}
}
+static gboolean
+aio_ctx_prepare(GSource *source, gint *timeout)
+{
+ AioContext *ctx = (AioContext *) source;
+ uint32_t wait = -1;
+ aio_bh_update_timeout(ctx, &wait);
+
+ if (wait != -1) {
+ *timeout = MIN(*timeout, wait);
+ return wait == 0;
+ }
+
+ return false;
+}
+
+static gboolean
+aio_ctx_check(GSource *source)
+{
+ AioContext *ctx = (AioContext *) source;
+ QEMUBH *bh;
+
+ for (bh = ctx->first_bh; bh; bh = bh->next) {
+ if (!bh->deleted && bh->scheduled) {
+ return true;
+ }
+ }
+ return aio_pending(ctx);
+}
+
+static gboolean
+aio_ctx_dispatch(GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ AioContext *ctx = (AioContext *) source;
+
+ assert(callback == NULL);
+ aio_poll(ctx, false);
+ return true;
+}
+
+static GSourceFuncs aio_source_funcs = {
+ aio_ctx_prepare,
+ aio_ctx_check,
+ aio_ctx_dispatch,
+ NULL
+};
+
+GSource *aio_get_g_source(AioContext *ctx)
+{
+ g_source_ref(&ctx->source);
+ return &ctx->source;
+}
AioContext *aio_context_new(void)
{
- return g_new0(AioContext, 1);
+ return (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext));
+}
+
+void aio_context_ref(AioContext *ctx)
+{
+ g_source_ref(&ctx->source);
+}
+
+void aio_context_unref(AioContext *ctx)
+{
+ g_source_unref(&ctx->source);
}
void aio_flush(AioContext *ctx)
diff --git a/qemu-aio.h b/qemu-aio.h
index ac24896..aedf66c 100644
--- a/qemu-aio.h
+++ b/qemu-aio.h
@@ -44,6 +44,8 @@ typedef void QEMUBHFunc(void *opaque);
typedef void IOHandler(void *opaque);
typedef struct AioContext {
+ GSource source;
+
/* The list of registered AIO handlers */
QLIST_HEAD(, AioHandler) aio_handlers;
@@ -75,6 +77,22 @@ typedef int (AioFlushEventNotifierHandler)(EventNotifier *e);
AioContext *aio_context_new(void);
/**
+ * aio_context_ref:
+ * @ctx: The AioContext to operate on.
+ *
+ * Add a reference to an AioContext.
+ */
+void aio_context_ref(AioContext *ctx);
+
+/**
+ * aio_context_unref:
+ * @ctx: The AioContext to operate on.
+ *
+ * Drop a reference to an AioContext.
+ */
+void aio_context_unref(AioContext *ctx);
+
+/**
* aio_bh_new: Allocate a new bottom half structure.
*
* Bottom halves are lightweight callbacks whose invocation is guaranteed
@@ -188,6 +206,11 @@ void aio_set_event_notifier(AioContext *ctx,
EventNotifierHandler *io_read,
AioFlushEventNotifierHandler *io_flush);
+/* Return a GSource that lets the main loop poll the file descriptors attached
+ * to this AioContext.
+ */
+GSource *aio_get_g_source(AioContext *ctx);
+
/* Functions to operate on the main QEMU AioContext. */
void qemu_aio_flush(void);
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 25/39] aio: add aio_notify
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (23 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 24/39] aio: make AioContexts GSources Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 26/39] aio: call aio_notify after setting I/O handlers Paolo Bonzini
` (14 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
With this change async.c does not rely anymore on any service from
main-loop.c, i.e. it is completely self-contained.
Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
async.c | 30 ++++++++++++++++++++++++++----
qemu-aio.h | 18 ++++++++++++++++++
2 file modificati, 44 inserzioni(+), 4 rimozioni(-)
diff --git a/async.c b/async.c
index 4ffdd98..564526f 100644
--- a/async.c
+++ b/async.c
@@ -30,6 +30,7 @@
/* bottom halves (can be seen as timers which expire ASAP) */
struct QEMUBH {
+ AioContext *ctx;
QEMUBHFunc *cb;
void *opaque;
QEMUBH *next;
@@ -42,6 +43,7 @@ QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
{
QEMUBH *bh;
bh = g_malloc0(sizeof(QEMUBH));
+ bh->ctx = ctx;
bh->cb = cb;
bh->opaque = opaque;
bh->next = ctx->first_bh;
@@ -101,8 +103,7 @@ void qemu_bh_schedule(QEMUBH *bh)
return;
bh->scheduled = 1;
bh->idle = 0;
- /* stop the currently executing CPU to execute the BH ASAP */
- qemu_notify_event();
+ aio_notify(bh->ctx);
}
void qemu_bh_cancel(QEMUBH *bh)
@@ -177,11 +178,20 @@ aio_ctx_dispatch(GSource *source,
return true;
}
+static void
+aio_ctx_finalize(GSource *source)
+{
+ AioContext *ctx = (AioContext *) source;
+
+ aio_set_event_notifier(ctx, &ctx->notifier, NULL, NULL);
+ event_notifier_cleanup(&ctx->notifier);
+}
+
static GSourceFuncs aio_source_funcs = {
aio_ctx_prepare,
aio_ctx_check,
aio_ctx_dispatch,
- NULL
+ aio_ctx_finalize
};
GSource *aio_get_g_source(AioContext *ctx)
@@ -190,9 +200,21 @@ GSource *aio_get_g_source(AioContext *ctx)
return &ctx->source;
}
+void aio_notify(AioContext *ctx)
+{
+ event_notifier_set(&ctx->notifier);
+}
+
AioContext *aio_context_new(void)
{
- return (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext));
+ AioContext *ctx;
+ ctx = (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext));
+ event_notifier_init(&ctx->notifier, false);
+ aio_set_event_notifier(ctx, &ctx->notifier,
+ (EventNotifierHandler *)
+ event_notifier_test_and_clear, NULL);
+
+ return ctx;
}
void aio_context_ref(AioContext *ctx)
diff --git a/qemu-aio.h b/qemu-aio.h
index aedf66c..2354617 100644
--- a/qemu-aio.h
+++ b/qemu-aio.h
@@ -62,6 +62,9 @@ typedef struct AioContext {
* no callbacks are removed while we're walking and dispatching callbacks.
*/
int walking_bh;
+
+ /* Used for aio_notify. */
+ EventNotifier notifier;
} AioContext;
/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */
@@ -102,6 +105,21 @@ void aio_context_unref(AioContext *ctx);
QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque);
/**
+ * aio_notify: Force processing of pending events.
+ *
+ * Similar to signaling a condition variable, aio_notify forces
+ * aio_wait to exit, so that the next call will re-examine pending events.
+ * The caller of aio_notify will usually call aio_wait again very soon,
+ * or go through another iteration of the GLib main loop. Hence, aio_notify
+ * also has the side effect of recalculating the sets of file descriptors
+ * that the main loop waits for.
+ *
+ * Calling aio_notify is rarely necessary, because for example scheduling
+ * a bottom half calls it already.
+ */
+void aio_notify(AioContext *ctx);
+
+/**
* aio_bh_poll: Poll bottom halves for an AioContext.
*
* These are internal functions used by the QEMU main loop.
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 26/39] aio: call aio_notify after setting I/O handlers
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (24 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 25/39] aio: add aio_notify Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 27/39] main-loop: use GSource to poll AIO file descriptors Paolo Bonzini
` (13 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
In the current code, this is done by qemu_set_fd_handler2, which is
called by qemu_aio_set_fd_handler. We need to keep the same behavior
even after removing the call to qemu_set_fd_handler2.
Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
aio-posix.c | 2 ++
aio-win32.c | 2 ++
2 file modificati, 4 inserzioni(+)
diff --git a/aio-posix.c b/aio-posix.c
index 65b2607..05cc84e 100644
--- a/aio-posix.c
+++ b/aio-posix.c
@@ -89,6 +89,8 @@ void aio_set_fd_handler(AioContext *ctx,
node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP : 0);
node->pfd.events |= (io_write ? G_IO_OUT : 0);
}
+
+ aio_notify(ctx);
}
void aio_set_event_notifier(AioContext *ctx,
diff --git a/aio-win32.c b/aio-win32.c
index e460bd8..a84eb71 100644
--- a/aio-win32.c
+++ b/aio-win32.c
@@ -75,6 +75,8 @@ void aio_set_event_notifier(AioContext *ctx,
node->io_notify = io_notify;
node->io_flush = io_flush;
}
+
+ aio_notify(ctx);
}
bool aio_pending(AioContext *ctx)
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 27/39] main-loop: use GSource to poll AIO file descriptors
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (25 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 26/39] aio: call aio_notify after setting I/O handlers Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 28/39] main-loop: use aio_notify for qemu_notify_event Paolo Bonzini
` (12 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
This lets us remove the hooks for the main loop in async.c.
Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
main-loop.c | 23 ++++++-----------------
main-loop.h | 1 -
2 file modificati, 6 inserzioni(+), 18 rimozioni(-)
diff --git a/main-loop.c b/main-loop.c
index a86c275..365c9d3 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -205,6 +205,7 @@ static AioContext *qemu_aio_context;
int qemu_init_main_loop(void)
{
int ret;
+ GSource *src;
init_clocks();
init_timer_alarm();
@@ -222,6 +223,9 @@ int qemu_init_main_loop(void)
}
qemu_aio_context = aio_context_new();
+ src = aio_get_g_source(qemu_aio_context);
+ g_source_attach(src, NULL);
+ g_source_unref(src);
return 0;
}
@@ -484,8 +488,6 @@ int main_loop_wait(int nonblocking)
if (nonblocking) {
timeout = 0;
- } else {
- aio_bh_update_timeout(qemu_aio_context, &timeout);
}
/* poll any events */
@@ -508,10 +510,6 @@ int main_loop_wait(int nonblocking)
qemu_run_all_timers();
- /* Check bottom-halves last in case any of the earlier events triggered
- them. */
- qemu_bh_poll();
-
return ret;
}
@@ -522,11 +520,6 @@ QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
return aio_bh_new(qemu_aio_context, cb, opaque);
}
-int qemu_bh_poll(void)
-{
- return aio_bh_poll(qemu_aio_context);
-}
-
void qemu_aio_flush(void)
{
aio_flush(qemu_aio_context);
@@ -546,16 +539,12 @@ void qemu_aio_set_fd_handler(int fd,
{
aio_set_fd_handler(qemu_aio_context, fd, io_read, io_write, io_flush,
opaque);
-
- qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque);
}
+#endif
void qemu_aio_set_event_notifier(EventNotifier *notifier,
EventNotifierHandler *io_read,
AioFlushEventNotifierHandler *io_flush)
{
- qemu_aio_set_fd_handler(event_notifier_get_fd(notifier),
- (IOHandler *)io_read, NULL,
- (AioFlushHandler *)io_flush, notifier);
+ aio_set_event_notifier(qemu_aio_context, notifier, io_read, io_flush);
}
-#endif
diff --git a/main-loop.h b/main-loop.h
index 1d1a56b..326c742 100644
--- a/main-loop.h
+++ b/main-loop.h
@@ -302,6 +302,5 @@ void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int rc
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
void qemu_bh_schedule_idle(QEMUBH *bh);
-int qemu_bh_poll(void);
#endif
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 28/39] main-loop: use aio_notify for qemu_notify_event
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (26 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 27/39] main-loop: use GSource to poll AIO file descriptors Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 29/39] aio: clean up now-unused functions Paolo Bonzini
` (11 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
main-loop.c | 106 +++++-------------------------------------------------------
1 file modificato, 8 inserzioni(+), 98 rimozioni(-)
diff --git a/main-loop.c b/main-loop.c
index 365c9d3..e43c7c8 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -32,70 +32,6 @@
#include "compatfd.h"
-static int io_thread_fd = -1;
-
-void qemu_notify_event(void)
-{
- /* Write 8 bytes to be compatible with eventfd. */
- static const uint64_t val = 1;
- ssize_t ret;
-
- if (io_thread_fd == -1) {
- return;
- }
- do {
- ret = write(io_thread_fd, &val, sizeof(val));
- } while (ret < 0 && errno == EINTR);
-
- /* EAGAIN is fine, a read must be pending. */
- if (ret < 0 && errno != EAGAIN) {
- fprintf(stderr, "qemu_notify_event: write() failed: %s\n",
- strerror(errno));
- exit(1);
- }
-}
-
-static void qemu_event_read(void *opaque)
-{
- int fd = (intptr_t)opaque;
- ssize_t len;
- char buffer[512];
-
- /* Drain the notify pipe. For eventfd, only 8 bytes will be read. */
- do {
- len = read(fd, buffer, sizeof(buffer));
- } while ((len == -1 && errno == EINTR) || len == sizeof(buffer));
-}
-
-static int qemu_event_init(void)
-{
- int err;
- int fds[2];
-
- err = qemu_eventfd(fds);
- if (err == -1) {
- return -errno;
- }
- err = fcntl_setfl(fds[0], O_NONBLOCK);
- if (err < 0) {
- goto fail;
- }
- err = fcntl_setfl(fds[1], O_NONBLOCK);
- if (err < 0) {
- goto fail;
- }
- qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,
- (void *)(intptr_t)fds[0]);
-
- io_thread_fd = fds[1];
- return 0;
-
-fail:
- close(fds[0]);
- close(fds[1]);
- return err;
-}
-
/* If we have signalfd, we mask out the signals we want to handle and then
* use signalfd to listen for them. We rely on whatever the current signal
* handler is to dispatch the signals when we receive them.
@@ -165,43 +101,22 @@ static int qemu_signal_init(void)
#else /* _WIN32 */
-static HANDLE qemu_event_handle = NULL;
-
-static void dummy_event_handler(void *opaque)
-{
-}
-
-static int qemu_event_init(void)
+static int qemu_signal_init(void)
{
- qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (!qemu_event_handle) {
- fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError());
- return -1;
- }
- qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL);
return 0;
}
+#endif
+
+static AioContext *qemu_aio_context;
void qemu_notify_event(void)
{
- if (!qemu_event_handle) {
+ if (!qemu_aio_context) {
return;
}
- if (!SetEvent(qemu_event_handle)) {
- fprintf(stderr, "qemu_notify_event: SetEvent failed: %ld\n",
- GetLastError());
- exit(1);
- }
+ aio_notify(qemu_aio_context);
}
-static int qemu_signal_init(void)
-{
- return 0;
-}
-#endif
-
-static AioContext *qemu_aio_context;
-
int qemu_init_main_loop(void)
{
int ret;
@@ -216,12 +131,6 @@ int qemu_init_main_loop(void)
return ret;
}
- /* Note eventfd must be drained before signalfd handlers run */
- ret = qemu_event_init();
- if (ret) {
- return ret;
- }
-
qemu_aio_context = aio_context_new();
src = aio_get_g_source(qemu_aio_context);
g_source_attach(src, NULL);
@@ -411,7 +320,8 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
void qemu_fd_register(int fd)
{
- WSAEventSelect(fd, qemu_event_handle, FD_READ | FD_ACCEPT | FD_CLOSE |
+ WSAEventSelect(fd, event_notifier_get_handle(&qemu_aio_context->notifier),
+ FD_READ | FD_ACCEPT | FD_CLOSE |
FD_CONNECT | FD_WRITE | FD_OOB);
}
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 29/39] aio: clean up now-unused functions
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (27 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 28/39] main-loop: use aio_notify for qemu_notify_event Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 30/39] linux-aio: use event notifiers Paolo Bonzini
` (10 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Some cleanups can now be made, now that the main loop does not anymore need
hooks into the bottom half code.
Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
async.c | 23 +++++++----------------
oslib-posix.c | 31 -------------------------------
qemu-aio.h | 1 -
qemu-common.h | 1 -
4 file modificati, 7 inserzioni(+), 49 rimozioni(-)
diff --git a/async.c b/async.c
index 564526f..04f9dcb 100644
--- a/async.c
+++ b/async.c
@@ -117,16 +117,20 @@ void qemu_bh_delete(QEMUBH *bh)
bh->deleted = 1;
}
-void aio_bh_update_timeout(AioContext *ctx, uint32_t *timeout)
+static gboolean
+aio_ctx_prepare(GSource *source, gint *timeout)
{
+ AioContext *ctx = (AioContext *) source;
QEMUBH *bh;
+ bool scheduled = false;
for (bh = ctx->first_bh; bh; bh = bh->next) {
if (!bh->deleted && bh->scheduled) {
+ scheduled = true;
if (bh->idle) {
/* idle bottom halves will be polled at least
* every 10ms */
- *timeout = MIN(10, *timeout);
+ *timeout = 10;
} else {
/* non-idle bottom halves will be executed
* immediately */
@@ -135,21 +139,8 @@ void aio_bh_update_timeout(AioContext *ctx, uint32_t *timeout)
}
}
}
-}
-
-static gboolean
-aio_ctx_prepare(GSource *source, gint *timeout)
-{
- AioContext *ctx = (AioContext *) source;
- uint32_t wait = -1;
- aio_bh_update_timeout(ctx, &wait);
-
- if (wait != -1) {
- *timeout = MIN(*timeout, wait);
- return wait == 0;
- }
- return false;
+ return scheduled;
}
static gboolean
diff --git a/oslib-posix.c b/oslib-posix.c
index dbeb627..9db9c3d 100644
--- a/oslib-posix.c
+++ b/oslib-posix.c
@@ -61,9 +61,6 @@ static int running_on_valgrind = -1;
#ifdef CONFIG_LINUX
#include <sys/syscall.h>
#endif
-#ifdef CONFIG_EVENTFD
-#include <sys/eventfd.h>
-#endif
int qemu_get_thread_id(void)
{
@@ -183,34 +180,6 @@ int qemu_pipe(int pipefd[2])
return ret;
}
-/*
- * Creates an eventfd that looks like a pipe and has EFD_CLOEXEC set.
- */
-int qemu_eventfd(int fds[2])
-{
-#ifdef CONFIG_EVENTFD
- int ret;
-
- ret = eventfd(0, 0);
- if (ret >= 0) {
- fds[0] = ret;
- fds[1] = dup(ret);
- if (fds[1] == -1) {
- close(ret);
- return -1;
- }
- qemu_set_cloexec(ret);
- qemu_set_cloexec(fds[1]);
- return 0;
- }
- if (errno != ENOSYS) {
- return -1;
- }
-#endif
-
- return qemu_pipe(fds);
-}
-
int qemu_utimens(const char *path, const struct timespec *times)
{
struct timeval tv[2], tv_now;
diff --git a/qemu-aio.h b/qemu-aio.h
index 2354617..1b7eb6e 100644
--- a/qemu-aio.h
+++ b/qemu-aio.h
@@ -125,7 +125,6 @@ void aio_notify(AioContext *ctx);
* These are internal functions used by the QEMU main loop.
*/
int aio_bh_poll(AioContext *ctx);
-void aio_bh_update_timeout(AioContext *ctx, uint32_t *timeout);
/**
* qemu_bh_schedule: Schedule a bottom half.
diff --git a/qemu-common.h b/qemu-common.h
index 24e13cc..c3328d2 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -218,7 +218,6 @@ ssize_t qemu_recv_full(int fd, void *buf, size_t count, int flags)
QEMU_WARN_UNUSED_RESULT;
#ifndef _WIN32
-int qemu_eventfd(int pipefd[2]);
int qemu_pipe(int pipefd[2]);
#endif
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 30/39] linux-aio: use event notifiers
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (28 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 29/39] aio: clean up now-unused functions Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 31/39] qemu-thread: add QemuSemaphore Paolo Bonzini
` (9 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Since linux-aio already uses an eventfd, converting it to use the
EventNotifier-based API simplifies the code even though it is not
meant to be portable.
Reviewed-by: Anthony Liguori <anthony@codemonkey.ws>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
linux-aio.c | 49 +++++++++++++++++++------------------------------
1 file modificato, 19 inserzioni(+), 30 rimozioni(-)
diff --git a/linux-aio.c b/linux-aio.c
index f3d8ef3..d1afb46 100644
--- a/linux-aio.c
+++ b/linux-aio.c
@@ -11,8 +11,8 @@
#include "qemu-aio.h"
#include "qemu-queue.h"
#include "block/raw-posix-aio.h"
+#include "event_notifier.h"
-#include <sys/eventfd.h>
#include <libaio.h>
/*
@@ -38,7 +38,7 @@ struct qemu_laiocb {
struct qemu_laio_state {
io_context_t ctx;
- int efd;
+ EventNotifier e;
int count;
};
@@ -77,29 +77,17 @@ static void qemu_laio_process_completion(struct qemu_laio_state *s,
qemu_aio_release(laiocb);
}
-static void qemu_laio_completion_cb(void *opaque)
+static void qemu_laio_completion_cb(EventNotifier *e)
{
- struct qemu_laio_state *s = opaque;
+ struct qemu_laio_state *s = container_of(e, struct qemu_laio_state, e);
- while (1) {
+ while (event_notifier_test_and_clear(&s->e)) {
struct io_event events[MAX_EVENTS];
- uint64_t val;
- ssize_t ret;
struct timespec ts = { 0 };
int nevents, i;
do {
- ret = read(s->efd, &val, sizeof(val));
- } while (ret == -1 && errno == EINTR);
-
- if (ret == -1 && errno == EAGAIN)
- break;
-
- if (ret != 8)
- break;
-
- do {
- nevents = io_getevents(s->ctx, val, MAX_EVENTS, events, &ts);
+ nevents = io_getevents(s->ctx, MAX_EVENTS, MAX_EVENTS, events, &ts);
} while (nevents == -EINTR);
for (i = 0; i < nevents; i++) {
@@ -113,9 +101,9 @@ static void qemu_laio_completion_cb(void *opaque)
}
}
-static int qemu_laio_flush_cb(void *opaque)
+static int qemu_laio_flush_cb(EventNotifier *e)
{
- struct qemu_laio_state *s = opaque;
+ struct qemu_laio_state *s = container_of(e, struct qemu_laio_state, e);
return (s->count > 0) ? 1 : 0;
}
@@ -147,8 +135,9 @@ static void laio_cancel(BlockDriverAIOCB *blockacb)
* We might be able to do this slightly more optimal by removing the
* O_NONBLOCK flag.
*/
- while (laiocb->ret == -EINPROGRESS)
- qemu_laio_completion_cb(laiocb->ctx);
+ while (laiocb->ret == -EINPROGRESS) {
+ qemu_laio_completion_cb(&laiocb->ctx->e);
+ }
}
static AIOPool laio_pool = {
@@ -187,7 +176,7 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
__func__, type);
goto out_free_aiocb;
}
- io_set_eventfd(&laiocb->iocb, s->efd);
+ io_set_eventfd(&laiocb->iocb, event_notifier_get_fd(&s->e));
s->count++;
if (io_submit(s->ctx, 1, &iocbs) < 0)
@@ -206,21 +195,21 @@ void *laio_init(void)
struct qemu_laio_state *s;
s = g_malloc0(sizeof(*s));
- s->efd = eventfd(0, 0);
- if (s->efd == -1)
+ if (event_notifier_init(&s->e, false) < 0) {
goto out_free_state;
- fcntl(s->efd, F_SETFL, O_NONBLOCK);
+ }
- if (io_setup(MAX_EVENTS, &s->ctx) != 0)
+ if (io_setup(MAX_EVENTS, &s->ctx) != 0) {
goto out_close_efd;
+ }
- qemu_aio_set_fd_handler(s->efd, qemu_laio_completion_cb, NULL,
- qemu_laio_flush_cb, s);
+ qemu_aio_set_event_notifier(&s->e, qemu_laio_completion_cb,
+ qemu_laio_flush_cb);
return s;
out_close_efd:
- close(s->efd);
+ event_notifier_cleanup(&s->e);
out_free_state:
g_free(s);
return NULL;
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 31/39] qemu-thread: add QemuSemaphore
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (29 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 30/39] linux-aio: use event notifiers Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 32/39] aio: add generic thread-pool facility Paolo Bonzini
` (8 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
The new thread pool will use semaphores instead of condition
variables, because QemuCond does not have qemu_cond_timedwait.
(I also like it more this way).
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
Difference from previous submission: handle EINTR
qemu-thread-posix.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++
qemu-thread-posix.h | 5 ++++
qemu-thread-win32.c | 35 +++++++++++++++++++++++
qemu-thread-win32.h | 4 +++
qemu-thread.h | 7 +++++
5 file modificati, 131 inserzioni(+)
diff --git a/qemu-thread-posix.c b/qemu-thread-posix.c
index 8fbabda..6a3d3a1 100644
--- a/qemu-thread-posix.c
+++ b/qemu-thread-posix.c
@@ -17,6 +17,9 @@
#include <signal.h>
#include <stdint.h>
#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/time.h>
#include "qemu-thread.h"
static void error_exit(int err, const char *msg)
@@ -115,6 +118,83 @@ void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
error_exit(err, __func__);
}
+void qemu_sem_init(QemuSemaphore *sem, int init)
+{
+ int rc;
+
+ rc = sem_init(&sem->sem, 0, init);
+ if (rc < 0) {
+ error_exit(errno, __func__);
+ }
+}
+
+void qemu_sem_destroy(QemuSemaphore *sem)
+{
+ int rc;
+
+ rc = sem_destroy(&sem->sem);
+ if (rc < 0) {
+ error_exit(errno, __func__);
+ }
+}
+
+void qemu_sem_post(QemuSemaphore *sem)
+{
+ int rc;
+
+ rc = sem_post(&sem->sem);
+ if (rc < 0) {
+ error_exit(errno, __func__);
+ }
+}
+
+int qemu_sem_timedwait(QemuSemaphore *sem, int ms)
+{
+ int rc;
+
+ if (ms <= 0) {
+ /* This is cheaper than sem_timedwait. */
+ do {
+ rc = sem_trywait(&sem->sem);
+ } while (rc == -1 && errno == EINTR);
+ if (rc == -1 && errno == EAGAIN) {
+ return -1;
+ }
+ } else {
+ struct timeval tv;
+ struct timespec ts;
+ gettimeofday(&tv, NULL);
+ ts.tv_nsec = tv.tv_usec * 1000 + (ms % 1000) * 1000000;
+ ts.tv_sec = tv.tv_sec + ms / 1000;
+ if (ts.tv_nsec >= 1000000000) {
+ ts.tv_sec++;
+ ts.tv_nsec -= 1000000000;
+ }
+ do {
+ rc = sem_timedwait(&sem->sem, &ts);
+ } while (rc == -1 && errno == EINTR);
+ if (rc == -1 && errno == ETIMEDOUT) {
+ return -1;
+ }
+ }
+ if (rc < 0) {
+ error_exit(errno, __func__);
+ }
+ return 0;
+}
+
+void qemu_sem_wait(QemuSemaphore *sem)
+{
+ int rc;
+
+ do {
+ rc = sem_wait(&sem->sem);
+ } while (rc == -1 && errno == EINTR);
+ if (rc < 0) {
+ error_exit(errno, __func__);
+ }
+}
+
void qemu_thread_create(QemuThread *thread,
void *(*start_routine)(void*),
void *arg, int mode)
diff --git a/qemu-thread-posix.h b/qemu-thread-posix.h
index ee4618e..2542c15 100644
--- a/qemu-thread-posix.h
+++ b/qemu-thread-posix.h
@@ -1,6 +1,7 @@
#ifndef __QEMU_THREAD_POSIX_H
#define __QEMU_THREAD_POSIX_H 1
#include "pthread.h"
+#include <semaphore.h>
struct QemuMutex {
pthread_mutex_t lock;
@@ -10,6 +11,10 @@ struct QemuCond {
pthread_cond_t cond;
};
+struct QemuSemaphore {
+ sem_t sem;
+};
+
struct QemuThread {
pthread_t thread;
};
diff --git a/qemu-thread-win32.c b/qemu-thread-win32.c
index 177b398..4b3db60 100644
--- a/qemu-thread-win32.c
+++ b/qemu-thread-win32.c
@@ -192,6 +192,41 @@ void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
qemu_mutex_lock(mutex);
}
+void qemu_sem_init(QemuSemaphore *sem, int init)
+{
+ /* Manual reset. */
+ sem->sema = CreateSemaphore(NULL, init, LONG_MAX, NULL);
+}
+
+void qemu_sem_destroy(QemuSemaphore *sem)
+{
+ CloseHandle(sem->sema);
+}
+
+void qemu_sem_post(QemuSemaphore *sem)
+{
+ ReleaseSemaphore(sem->sema, 1, NULL);
+}
+
+int qemu_sem_timedwait(QemuSemaphore *sem, int ms)
+{
+ int rc = WaitForSingleObject(sem->sema, ms);
+ if (rc == WAIT_OBJECT_0) {
+ return 0;
+ }
+ if (rc != WAIT_TIMEOUT) {
+ error_exit(GetLastError(), __func__);
+ }
+ return -1;
+}
+
+void qemu_sem_wait(QemuSemaphore *sem)
+{
+ if (WaitForSingleObject(sem->sema, INFINITE) != WAIT_OBJECT_0) {
+ error_exit(GetLastError(), __func__);
+ }
+}
+
struct QemuThreadData {
/* Passed to win32_start_routine. */
void *(*start_routine)(void *);
diff --git a/qemu-thread-win32.h b/qemu-thread-win32.h
index b9d1be8..13adb95 100644
--- a/qemu-thread-win32.h
+++ b/qemu-thread-win32.h
@@ -13,6 +13,10 @@ struct QemuCond {
HANDLE continue_event;
};
+struct QemuSemaphore {
+ HANDLE sema;
+};
+
typedef struct QemuThreadData QemuThreadData;
struct QemuThread {
QemuThreadData *data;
diff --git a/qemu-thread.h b/qemu-thread.h
index 05fdaaf..3ee2f6b 100644
--- a/qemu-thread.h
+++ b/qemu-thread.h
@@ -6,6 +6,7 @@
typedef struct QemuMutex QemuMutex;
typedef struct QemuCond QemuCond;
+typedef struct QemuSemaphore QemuSemaphore;
typedef struct QemuThread QemuThread;
#ifdef _WIN32
@@ -38,6 +39,12 @@ void qemu_cond_signal(QemuCond *cond);
void qemu_cond_broadcast(QemuCond *cond);
void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex);
+void qemu_sem_init(QemuSemaphore *sem, int init);
+void qemu_sem_post(QemuSemaphore *sem);
+void qemu_sem_wait(QemuSemaphore *sem);
+int qemu_sem_timedwait(QemuSemaphore *sem, int ms);
+void qemu_sem_destroy(QemuSemaphore *sem);
+
void qemu_thread_create(QemuThread *thread,
void *(*start_routine)(void *),
void *arg, int mode);
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 32/39] aio: add generic thread-pool facility
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (30 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 31/39] qemu-thread: add QemuSemaphore Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 33/39] threadpool: do not take lock in event_notifier_ready Paolo Bonzini
` (7 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Add a generic thread-pool. The code is roughly based on posix-aio-compat.c,
with some changes, especially the following:
- use QemuSemaphore instead of QemuCond;
- separate the state of the thread from the return code of the worker
function. The return code is totally opaque for the thread pool;
- do not busy wait when doing cancellation.
A more generic threadpool (but still specific to I/O so that in the future
it can use special scheduling classes or PI mutexes) can have many uses:
it allows more flexibility in raw-posix.c and can more easily be extended
to Win32, and it will also be used to do an msync of the persistent bitmap.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
Difference from previous submission: add locking documentation,
fix locking in event_notifier_ready.
Makefile.objs | 2 +-
thread-pool.c | 282 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
thread-pool.h | 34 +++++++
trace-events | 5 ++
4 file modificati, 322 inserzioni(+). 1 rimozione(-)
create mode 100644 thread-pool.c
create mode 100644 thread-pool.h
diff --git a/Makefile.objs b/Makefile.objs
index a8ade04..f8ae031 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -43,7 +43,7 @@ coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o
block-obj-y = iov.o cache-utils.o qemu-option.o module.o async.o
block-obj-y += nbd.o block.o blockjob.o aes.o qemu-config.o
-block-obj-y += qemu-progress.o qemu-sockets.o uri.o notify.o
+block-obj-y += thread-pool.o qemu-progress.o qemu-sockets.o uri.o notify.o
block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y)
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
block-obj-$(CONFIG_POSIX) += event_notifier-posix.o aio-posix.o
diff --git a/thread-pool.c b/thread-pool.c
new file mode 100644
index 0000000..80749b7
--- /dev/null
+++ b/thread-pool.c
@@ -0,0 +1,282 @@
+/*
+ * QEMU block layer thread pool
+ *
+ * Copyright IBM, Corp. 2008
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+#include "qemu-common.h"
+#include "qemu-queue.h"
+#include "qemu-thread.h"
+#include "osdep.h"
+#include "qemu-coroutine.h"
+#include "trace.h"
+#include "block_int.h"
+#include "event_notifier.h"
+#include "thread-pool.h"
+
+static void do_spawn_thread(void);
+
+typedef struct ThreadPoolElement ThreadPoolElement;
+
+enum ThreadState {
+ THREAD_QUEUED,
+ THREAD_ACTIVE,
+ THREAD_DONE,
+ THREAD_CANCELED,
+};
+
+struct ThreadPoolElement {
+ BlockDriverAIOCB common;
+ ThreadPoolFunc *func;
+ void *arg;
+ enum ThreadState state;
+ int ret;
+
+ /* Access to this list is protected by lock. */
+ QTAILQ_ENTRY(ThreadPoolElement) reqs;
+
+ /* Access to this list is protected by the global mutex. */
+ QLIST_ENTRY(ThreadPoolElement) all;
+};
+
+static EventNotifier notifier;
+static QemuMutex lock;
+static QemuCond check_cancel;
+static QemuSemaphore sem;
+static int max_threads = 64;
+static QEMUBH *new_thread_bh;
+
+/* The following variables are protected by the global mutex. */
+static QLIST_HEAD(, ThreadPoolElement) head;
+
+/* The following variables are protected by lock. */
+static QTAILQ_HEAD(, ThreadPoolElement) request_list;
+static int cur_threads;
+static int idle_threads;
+static int new_threads; /* backlog of threads we need to create */
+static int pending_threads; /* threads created but not running yet */
+static int pending_cancellations; /* whether we need a cond_broadcast */
+
+static void *worker_thread(void *unused)
+{
+ qemu_mutex_lock(&lock);
+ pending_threads--;
+ do_spawn_thread();
+
+ while (1) {
+ ThreadPoolElement *req;
+ int ret;
+
+ do {
+ idle_threads++;
+ qemu_mutex_unlock(&lock);
+ ret = qemu_sem_timedwait(&sem, 10000);
+ qemu_mutex_lock(&lock);
+ idle_threads--;
+ } while (ret == -1 && !QTAILQ_EMPTY(&request_list));
+ if (ret == -1) {
+ break;
+ }
+
+ req = QTAILQ_FIRST(&request_list);
+ QTAILQ_REMOVE(&request_list, req, reqs);
+ req->state = THREAD_ACTIVE;
+ qemu_mutex_unlock(&lock);
+
+ ret = req->func(req->arg);
+
+ qemu_mutex_lock(&lock);
+ req->state = THREAD_DONE;
+ req->ret = ret;
+ if (pending_cancellations) {
+ qemu_cond_broadcast(&check_cancel);
+ }
+
+ event_notifier_set(¬ifier);
+ }
+
+ cur_threads--;
+ qemu_mutex_unlock(&lock);
+ return NULL;
+}
+
+static void do_spawn_thread(void)
+{
+ QemuThread t;
+
+ /* Runs with lock taken. */
+ if (!new_threads) {
+ return;
+ }
+
+ new_threads--;
+ pending_threads++;
+
+ qemu_thread_create(&t, worker_thread, NULL, QEMU_THREAD_DETACHED);
+}
+
+static void spawn_thread_bh_fn(void *opaque)
+{
+ qemu_mutex_lock(&lock);
+ do_spawn_thread();
+ qemu_mutex_unlock(&lock);
+}
+
+static void spawn_thread(void)
+{
+ cur_threads++;
+ new_threads++;
+ /* If there are threads being created, they will spawn new workers, so
+ * we don't spend time creating many threads in a loop holding a mutex or
+ * starving the current vcpu.
+ *
+ * If there are no idle threads, ask the main thread to create one, so we
+ * inherit the correct affinity instead of the vcpu affinity.
+ */
+ if (!pending_threads) {
+ qemu_bh_schedule(new_thread_bh);
+ }
+}
+
+static void event_notifier_ready(EventNotifier *notifier)
+{
+ ThreadPoolElement *elem, *next;
+
+ event_notifier_test_and_clear(notifier);
+restart:
+ QLIST_FOREACH_SAFE(elem, &head, all, next) {
+ if (elem->state != THREAD_CANCELED && elem->state != THREAD_DONE) {
+ continue;
+ }
+ if (elem->state == THREAD_DONE) {
+ trace_thread_pool_complete(elem, elem->common.opaque, elem->ret);
+ }
+ if (elem->state == THREAD_DONE && elem->common.cb) {
+ qemu_mutex_lock(&lock);
+ int ret = elem->ret;
+ qemu_mutex_unlock(&lock);
+ QLIST_REMOVE(elem, all);
+ elem->common.cb(elem->common.opaque, ret);
+ qemu_aio_release(elem);
+ goto restart;
+ } else {
+ /* remove the request */
+ QLIST_REMOVE(elem, all);
+ qemu_aio_release(elem);
+ }
+ }
+}
+
+static int thread_pool_active(EventNotifier *notifier)
+{
+ return !QLIST_EMPTY(&head);
+}
+
+static void thread_pool_cancel(BlockDriverAIOCB *acb)
+{
+ ThreadPoolElement *elem = (ThreadPoolElement *)acb;
+
+ trace_thread_pool_cancel(elem, elem->common.opaque);
+
+ qemu_mutex_lock(&lock);
+ if (elem->state == THREAD_QUEUED &&
+ /* No thread has yet started working on elem. we can try to "steal"
+ * the item from the worker if we can get a signal from the
+ * semaphore. Because this is non-blocking, we can do it with
+ * the lock taken and ensure that elem will remain THREAD_QUEUED.
+ */
+ qemu_sem_timedwait(&sem, 0) == 0) {
+ QTAILQ_REMOVE(&request_list, elem, reqs);
+ elem->state = THREAD_CANCELED;
+ event_notifier_set(¬ifier);
+ } else {
+ pending_cancellations++;
+ while (elem->state != THREAD_CANCELED && elem->state != THREAD_DONE) {
+ qemu_cond_wait(&check_cancel, &lock);
+ }
+ pending_cancellations--;
+ }
+ qemu_mutex_unlock(&lock);
+}
+
+static AIOPool thread_pool_cb_pool = {
+ .aiocb_size = sizeof(ThreadPoolElement),
+ .cancel = thread_pool_cancel,
+};
+
+BlockDriverAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ ThreadPoolElement *req;
+
+ req = qemu_aio_get(&thread_pool_cb_pool, NULL, cb, opaque);
+ req->func = func;
+ req->arg = arg;
+ req->state = THREAD_QUEUED;
+
+ QLIST_INSERT_HEAD(&head, req, all);
+
+ trace_thread_pool_submit(req, arg);
+
+ qemu_mutex_lock(&lock);
+ if (idle_threads == 0 && cur_threads < max_threads) {
+ spawn_thread();
+ }
+ QTAILQ_INSERT_TAIL(&request_list, req, reqs);
+ qemu_mutex_unlock(&lock);
+ qemu_sem_post(&sem);
+ return &req->common;
+}
+
+typedef struct ThreadPoolCo {
+ Coroutine *co;
+ int ret;
+} ThreadPoolCo;
+
+static void thread_pool_co_cb(void *opaque, int ret)
+{
+ ThreadPoolCo *co = opaque;
+
+ co->ret = ret;
+ qemu_coroutine_enter(co->co, NULL);
+}
+
+int coroutine_fn thread_pool_submit_co(ThreadPoolFunc *func, void *arg)
+{
+ ThreadPoolCo tpc = { .co = qemu_coroutine_self(), .ret = -EINPROGRESS };
+ assert(qemu_in_coroutine());
+ thread_pool_submit_aio(func, arg, thread_pool_co_cb, &tpc);
+ qemu_coroutine_yield();
+ return tpc.ret;
+}
+
+void thread_pool_submit(ThreadPoolFunc *func, void *arg)
+{
+ thread_pool_submit_aio(func, arg, NULL, NULL);
+}
+
+static void thread_pool_init(void)
+{
+ QLIST_INIT(&head);
+ event_notifier_init(¬ifier, false);
+ qemu_mutex_init(&lock);
+ qemu_cond_init(&check_cancel);
+ qemu_sem_init(&sem, 0);
+ qemu_aio_set_event_notifier(¬ifier, event_notifier_ready,
+ thread_pool_active);
+
+ QTAILQ_INIT(&request_list);
+ new_thread_bh = qemu_bh_new(spawn_thread_bh_fn, NULL);
+}
+
+block_init(thread_pool_init)
diff --git a/thread-pool.h b/thread-pool.h
new file mode 100644
index 0000000..378a4ac
--- /dev/null
+++ b/thread-pool.h
@@ -0,0 +1,34 @@
+/*
+ * QEMU block layer thread pool
+ *
+ * Copyright IBM, Corp. 2008
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#ifndef QEMU_THREAD_POOL_H
+#define QEMU_THREAD_POOL_H 1
+
+#include "qemu-common.h"
+#include "qemu-queue.h"
+#include "qemu-thread.h"
+#include "qemu-coroutine.h"
+#include "block_int.h"
+
+typedef int ThreadPoolFunc(void *opaque);
+
+BlockDriverAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg,
+ BlockDriverCompletionFunc *cb, void *opaque);
+int coroutine_fn thread_pool_submit_co(ThreadPoolFunc *func, void *arg);
+void thread_pool_submit(ThreadPoolFunc *func, void *arg);
+
+#endif
diff --git a/trace-events b/trace-events
index e2d4580..58c18eb 100644
--- a/trace-events
+++ b/trace-events
@@ -90,6 +90,11 @@ virtio_blk_rw_complete(void *req, int ret) "req %p ret %d"
virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
virtio_blk_handle_read(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
+# thread-pool.c
+thread_pool_submit(void *req, void *opaque) "req %p opaque %p"
+thread_pool_complete(void *req, void *opaque, int ret) "req %p opaque %p ret %d"
+thread_pool_cancel(void *req, void *opaque) "req %p opaque %p"
+
# posix-aio-compat.c
paio_submit(void *acb, void *opaque, int64_t sector_num, int nb_sectors, int type) "acb %p opaque %p sector_num %"PRId64" nb_sectors %d type %d"
paio_complete(void *acb, void *opaque, int ret) "acb %p opaque %p ret %d"
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 33/39] threadpool: do not take lock in event_notifier_ready
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (31 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 32/39] aio: add generic thread-pool facility Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 34/39] block: switch posix-aio-compat to threadpool Paolo Bonzini
` (6 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
The ordering is:
worker thread consumer thread
-------------------------------------------------------------------
write ret event_notifier_test_and_clear
wmb() read state
write state rmb()
event_notifier_set read ret
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
New patch.
thread-pool.c | 19 +++++++++++++------
1 file modificato, 13 inserzioni(+), 6 rimozioni(-)
diff --git a/thread-pool.c b/thread-pool.c
index 80749b7..651b324 100644
--- a/thread-pool.c
+++ b/thread-pool.c
@@ -39,6 +39,11 @@ struct ThreadPoolElement {
BlockDriverAIOCB common;
ThreadPoolFunc *func;
void *arg;
+
+ /* Moving state out of THREAD_QUEUED is protected by lock. After
+ * that, only the worker thread can write to it. Reads and writes
+ * of state and ret are ordered with memory barriers.
+ */
enum ThreadState state;
int ret;
@@ -95,9 +100,12 @@ static void *worker_thread(void *unused)
ret = req->func(req->arg);
- qemu_mutex_lock(&lock);
- req->state = THREAD_DONE;
req->ret = ret;
+ /* Write ret before state. */
+ smp_wmb();
+ req->state = THREAD_DONE;
+
+ qemu_mutex_lock(&lock);
if (pending_cancellations) {
qemu_cond_broadcast(&check_cancel);
}
@@ -162,11 +170,10 @@ restart:
trace_thread_pool_complete(elem, elem->common.opaque, elem->ret);
}
if (elem->state == THREAD_DONE && elem->common.cb) {
- qemu_mutex_lock(&lock);
- int ret = elem->ret;
- qemu_mutex_unlock(&lock);
QLIST_REMOVE(elem, all);
- elem->common.cb(elem->common.opaque, ret);
+ /* Read state before ret. */
+ smp_rmb();
+ elem->common.cb(elem->common.opaque, elem->ret);
qemu_aio_release(elem);
goto restart;
} else {
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 34/39] block: switch posix-aio-compat to threadpool
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (32 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 33/39] threadpool: do not take lock in event_notifier_ready Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 35/39] raw: merge posix-aio-compat.c into block/raw-posix.c Paolo Bonzini
` (5 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
This is not meant for portability, but to remove code duplication.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
block/raw-posix-aio.h | 1 -
block/raw-posix.c | 12 +-
posix-aio-compat.c | 427 +++++---------------------------------------------
3 file modificati, 41 inserzioni(+), 399 rimozioni(-)
diff --git a/block/raw-posix-aio.h b/block/raw-posix-aio.h
index ba118f6..6725135 100644
--- a/block/raw-posix-aio.h
+++ b/block/raw-posix-aio.h
@@ -28,7 +28,6 @@
/* posix-aio-compat.c - thread pool based implementation */
-int paio_init(void);
BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type);
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 28d439f..9ae2c50 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -266,14 +266,10 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
}
s->fd = fd;
- /* We're falling back to POSIX AIO in some cases so init always */
- if (paio_init() < 0) {
- goto out_close;
- }
-
#ifdef CONFIG_LINUX_AIO
if (raw_set_aio(&s->aio_ctx, &s->use_aio, bdrv_flags)) {
- goto out_close;
+ qemu_close(fd);
+ return -errno;
}
#endif
@@ -284,10 +280,6 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
#endif
return 0;
-
-out_close:
- qemu_close(fd);
- return -errno;
}
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
diff --git a/posix-aio-compat.c b/posix-aio-compat.c
index 96e4daf..4a1e3d3 100644
--- a/posix-aio-compat.c
+++ b/posix-aio-compat.c
@@ -28,13 +28,12 @@
#include "sysemu.h"
#include "qemu-common.h"
#include "trace.h"
+#include "thread-pool.h"
#include "block_int.h"
#include "iov.h"
#include "block/raw-posix-aio.h"
-static void do_spawn_thread(void);
-
struct qemu_paiocb {
BlockDriverAIOCB common;
int aio_fildes;
@@ -46,82 +45,15 @@ struct qemu_paiocb {
size_t aio_nbytes;
#define aio_ioctl_cmd aio_nbytes /* for QEMU_AIO_IOCTL */
off_t aio_offset;
-
- QTAILQ_ENTRY(qemu_paiocb) node;
int aio_type;
- ssize_t ret;
- int active;
- struct qemu_paiocb *next;
};
-typedef struct PosixAioState {
- int rfd, wfd;
- struct qemu_paiocb *first_aio;
-} PosixAioState;
-
-
-static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
-static pthread_t thread_id;
-static pthread_attr_t attr;
-static int max_threads = 64;
-static int cur_threads = 0;
-static int idle_threads = 0;
-static int new_threads = 0; /* backlog of threads we need to create */
-static int pending_threads = 0; /* threads created but not running yet */
-static QEMUBH *new_thread_bh;
-static QTAILQ_HEAD(, qemu_paiocb) request_list;
-
#ifdef CONFIG_PREADV
static int preadv_present = 1;
#else
static int preadv_present = 0;
#endif
-static void die2(int err, const char *what)
-{
- fprintf(stderr, "%s failed: %s\n", what, strerror(err));
- abort();
-}
-
-static void die(const char *what)
-{
- die2(errno, what);
-}
-
-static void mutex_lock(pthread_mutex_t *mutex)
-{
- int ret = pthread_mutex_lock(mutex);
- if (ret) die2(ret, "pthread_mutex_lock");
-}
-
-static void mutex_unlock(pthread_mutex_t *mutex)
-{
- int ret = pthread_mutex_unlock(mutex);
- if (ret) die2(ret, "pthread_mutex_unlock");
-}
-
-static int cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
- struct timespec *ts)
-{
- int ret = pthread_cond_timedwait(cond, mutex, ts);
- if (ret && ret != ETIMEDOUT) die2(ret, "pthread_cond_timedwait");
- return ret;
-}
-
-static void cond_signal(pthread_cond_t *cond)
-{
- int ret = pthread_cond_signal(cond);
- if (ret) die2(ret, "pthread_cond_signal");
-}
-
-static void thread_create(pthread_t *thread, pthread_attr_t *attr,
- void *(*start_routine)(void*), void *arg)
-{
- int ret = pthread_create(thread, attr, start_routine, arg);
- if (ret) die2(ret, "pthread_create");
-}
-
static ssize_t handle_aiocb_ioctl(struct qemu_paiocb *aiocb)
{
int ret;
@@ -310,286 +242,54 @@ static ssize_t handle_aiocb_rw(struct qemu_paiocb *aiocb)
return nbytes;
}
-static void posix_aio_notify_event(void);
-
-static void *aio_thread(void *unused)
+static int aio_worker(void *arg)
{
- mutex_lock(&lock);
- pending_threads--;
- mutex_unlock(&lock);
- do_spawn_thread();
-
- while (1) {
- struct qemu_paiocb *aiocb;
- ssize_t ret = 0;
- qemu_timeval tv;
- struct timespec ts;
-
- qemu_gettimeofday(&tv);
- ts.tv_sec = tv.tv_sec + 10;
- ts.tv_nsec = 0;
-
- mutex_lock(&lock);
-
- while (QTAILQ_EMPTY(&request_list) &&
- !(ret == ETIMEDOUT)) {
- idle_threads++;
- ret = cond_timedwait(&cond, &lock, &ts);
- idle_threads--;
+ struct qemu_paiocb *aiocb = arg;
+ ssize_t ret = 0;
+
+ switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
+ case QEMU_AIO_READ:
+ ret = handle_aiocb_rw(aiocb);
+ if (ret >= 0 && ret < aiocb->aio_nbytes && aiocb->common.bs->growable) {
+ /* A short read means that we have reached EOF. Pad the buffer
+ * with zeros for bytes after EOF. */
+ iov_memset(aiocb->aio_iov, aiocb->aio_niov, ret,
+ 0, aiocb->aio_nbytes - ret);
+
+ ret = aiocb->aio_nbytes;
}
-
- if (QTAILQ_EMPTY(&request_list))
- break;
-
- aiocb = QTAILQ_FIRST(&request_list);
- QTAILQ_REMOVE(&request_list, aiocb, node);
- aiocb->active = 1;
- mutex_unlock(&lock);
-
- switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
- case QEMU_AIO_READ:
- ret = handle_aiocb_rw(aiocb);
- if (ret >= 0 && ret < aiocb->aio_nbytes && aiocb->common.bs->growable) {
- /* A short read means that we have reached EOF. Pad the buffer
- * with zeros for bytes after EOF. */
- iov_memset(aiocb->aio_iov, aiocb->aio_niov, ret,
- 0, aiocb->aio_nbytes - ret);
-
- ret = aiocb->aio_nbytes;
- }
- break;
- case QEMU_AIO_WRITE:
- ret = handle_aiocb_rw(aiocb);
- break;
- case QEMU_AIO_FLUSH:
- ret = handle_aiocb_flush(aiocb);
- break;
- case QEMU_AIO_IOCTL:
- ret = handle_aiocb_ioctl(aiocb);
- break;
- default:
- fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
+ if (ret == aiocb->aio_nbytes) {
+ ret = 0;
+ } else if (ret >= 0 && ret < aiocb->aio_nbytes) {
ret = -EINVAL;
- break;
}
-
- mutex_lock(&lock);
- aiocb->ret = ret;
- mutex_unlock(&lock);
-
- posix_aio_notify_event();
- }
-
- cur_threads--;
- mutex_unlock(&lock);
-
- return NULL;
-}
-
-static void do_spawn_thread(void)
-{
- sigset_t set, oldset;
-
- mutex_lock(&lock);
- if (!new_threads) {
- mutex_unlock(&lock);
- return;
- }
-
- new_threads--;
- pending_threads++;
-
- mutex_unlock(&lock);
-
- /* block all signals */
- if (sigfillset(&set)) die("sigfillset");
- if (sigprocmask(SIG_SETMASK, &set, &oldset)) die("sigprocmask");
-
- thread_create(&thread_id, &attr, aio_thread, NULL);
-
- if (sigprocmask(SIG_SETMASK, &oldset, NULL)) die("sigprocmask restore");
-}
-
-static void spawn_thread_bh_fn(void *opaque)
-{
- do_spawn_thread();
-}
-
-static void spawn_thread(void)
-{
- cur_threads++;
- new_threads++;
- /* If there are threads being created, they will spawn new workers, so
- * we don't spend time creating many threads in a loop holding a mutex or
- * starving the current vcpu.
- *
- * If there are no idle threads, ask the main thread to create one, so we
- * inherit the correct affinity instead of the vcpu affinity.
- */
- if (!pending_threads) {
- qemu_bh_schedule(new_thread_bh);
- }
-}
-
-static void qemu_paio_submit(struct qemu_paiocb *aiocb)
-{
- aiocb->ret = -EINPROGRESS;
- aiocb->active = 0;
- mutex_lock(&lock);
- if (idle_threads == 0 && cur_threads < max_threads)
- spawn_thread();
- QTAILQ_INSERT_TAIL(&request_list, aiocb, node);
- mutex_unlock(&lock);
- cond_signal(&cond);
-}
-
-static ssize_t qemu_paio_return(struct qemu_paiocb *aiocb)
-{
- ssize_t ret;
-
- mutex_lock(&lock);
- ret = aiocb->ret;
- mutex_unlock(&lock);
-
- return ret;
-}
-
-static int qemu_paio_error(struct qemu_paiocb *aiocb)
-{
- ssize_t ret = qemu_paio_return(aiocb);
-
- if (ret < 0)
- ret = -ret;
- else
- ret = 0;
-
- return ret;
-}
-
-static void posix_aio_read(void *opaque)
-{
- PosixAioState *s = opaque;
- struct qemu_paiocb *acb, **pacb;
- int ret;
- ssize_t len;
-
- /* read all bytes from signal pipe */
- for (;;) {
- char bytes[16];
-
- len = read(s->rfd, bytes, sizeof(bytes));
- if (len == -1 && errno == EINTR)
- continue; /* try again */
- if (len == sizeof(bytes))
- continue; /* more to read */
break;
- }
-
- for(;;) {
- pacb = &s->first_aio;
- for(;;) {
- acb = *pacb;
- if (!acb)
- return;
-
- ret = qemu_paio_error(acb);
- if (ret == ECANCELED) {
- /* remove the request */
- *pacb = acb->next;
- qemu_aio_release(acb);
- } else if (ret != EINPROGRESS) {
- /* end of aio */
- if (ret == 0) {
- ret = qemu_paio_return(acb);
- if (ret == acb->aio_nbytes)
- ret = 0;
- else
- ret = -EINVAL;
- } else {
- ret = -ret;
- }
-
- trace_paio_complete(acb, acb->common.opaque, ret);
-
- /* remove the request */
- *pacb = acb->next;
- /* call the callback */
- acb->common.cb(acb->common.opaque, ret);
- qemu_aio_release(acb);
- break;
- } else {
- pacb = &acb->next;
- }
- }
- }
-}
-
-static int posix_aio_flush(void *opaque)
-{
- PosixAioState *s = opaque;
- return !!s->first_aio;
-}
-
-static PosixAioState *posix_aio_state;
-
-static void posix_aio_notify_event(void)
-{
- char byte = 0;
- ssize_t ret;
-
- ret = write(posix_aio_state->wfd, &byte, sizeof(byte));
- if (ret < 0 && errno != EAGAIN)
- die("write()");
-}
-
-static void paio_remove(struct qemu_paiocb *acb)
-{
- struct qemu_paiocb **pacb;
-
- /* remove the callback from the queue */
- pacb = &posix_aio_state->first_aio;
- for(;;) {
- if (*pacb == NULL) {
- fprintf(stderr, "paio_remove: aio request not found!\n");
- break;
- } else if (*pacb == acb) {
- *pacb = acb->next;
- qemu_aio_release(acb);
- break;
+ case QEMU_AIO_WRITE:
+ ret = handle_aiocb_rw(aiocb);
+ if (ret == aiocb->aio_nbytes) {
+ ret = 0;
+ } else if (ret >= 0 && ret < aiocb->aio_nbytes) {
+ ret = -EINVAL;
}
- pacb = &(*pacb)->next;
- }
-}
-
-static void paio_cancel(BlockDriverAIOCB *blockacb)
-{
- struct qemu_paiocb *acb = (struct qemu_paiocb *)blockacb;
- int active = 0;
-
- trace_paio_cancel(acb, acb->common.opaque);
-
- mutex_lock(&lock);
- if (!acb->active) {
- QTAILQ_REMOVE(&request_list, acb, node);
- acb->ret = -ECANCELED;
- } else if (acb->ret == -EINPROGRESS) {
- active = 1;
- }
- mutex_unlock(&lock);
-
- if (active) {
- /* fail safe: if the aio could not be canceled, we wait for
- it */
- while (qemu_paio_error(acb) == EINPROGRESS)
- ;
+ break;
+ case QEMU_AIO_FLUSH:
+ ret = handle_aiocb_flush(aiocb);
+ break;
+ case QEMU_AIO_IOCTL:
+ ret = handle_aiocb_ioctl(aiocb);
+ break;
+ default:
+ fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
+ ret = -EINVAL;
+ break;
}
- paio_remove(acb);
+ qemu_aio_release(aiocb);
+ return ret;
}
static AIOPool raw_aio_pool = {
.aiocb_size = sizeof(struct qemu_paiocb),
- .cancel = paio_cancel,
};
BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
@@ -609,12 +309,8 @@ BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
acb->aio_nbytes = nb_sectors * 512;
acb->aio_offset = sector_num * 512;
- acb->next = posix_aio_state->first_aio;
- posix_aio_state->first_aio = acb;
-
trace_paio_submit(acb, opaque, sector_num, nb_sectors, type);
- qemu_paio_submit(acb);
- return &acb->common;
+ return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
}
BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
@@ -630,50 +326,5 @@ BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
acb->aio_ioctl_buf = buf;
acb->aio_ioctl_cmd = req;
- acb->next = posix_aio_state->first_aio;
- posix_aio_state->first_aio = acb;
-
- qemu_paio_submit(acb);
- return &acb->common;
-}
-
-int paio_init(void)
-{
- PosixAioState *s;
- int fds[2];
- int ret;
-
- if (posix_aio_state)
- return 0;
-
- s = g_malloc(sizeof(PosixAioState));
-
- s->first_aio = NULL;
- if (qemu_pipe(fds) == -1) {
- fprintf(stderr, "failed to create pipe\n");
- g_free(s);
- return -1;
- }
-
- s->rfd = fds[0];
- s->wfd = fds[1];
-
- fcntl(s->rfd, F_SETFL, O_NONBLOCK);
- fcntl(s->wfd, F_SETFL, O_NONBLOCK);
-
- qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush, s);
-
- ret = pthread_attr_init(&attr);
- if (ret)
- die2(ret, "pthread_attr_init");
-
- ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- if (ret)
- die2(ret, "pthread_attr_setdetachstate");
-
- QTAILQ_INIT(&request_list);
- new_thread_bh = qemu_bh_new(spawn_thread_bh_fn, NULL);
-
- posix_aio_state = s;
- return 0;
+ return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
}
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 35/39] raw: merge posix-aio-compat.c into block/raw-posix.c
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (33 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 34/39] block: switch posix-aio-compat to threadpool Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-11-02 15:00 ` Peter Maydell
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 36/39] raw-posix: rename raw-posix-aio.h, hide unavailable prototypes Paolo Bonzini
` (4 subsequent siblings)
39 siblings, 1 reply; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Making the qemu_paiocb specific to raw devices will let us access members
of the BDRVRawState arbitrarily.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
Makefile.objs | 1 -
block/raw-posix-aio.h | 8 --
block/raw-posix.c | 294 ++++++++++++++++++++++++++++++++++++++++++++
posix-aio-compat.c | 330 --------------------------------------------------
4 file modificati, 294 inserzioni(+), 339 rimozioni(-)
delete mode 100644 posix-aio-compat.c
diff --git a/Makefile.objs b/Makefile.objs
index f8ae031..35c2355 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -45,7 +45,6 @@ block-obj-y = iov.o cache-utils.o qemu-option.o module.o async.o
block-obj-y += nbd.o block.o blockjob.o aes.o qemu-config.o
block-obj-y += thread-pool.o qemu-progress.o qemu-sockets.o uri.o notify.o
block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y)
-block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
block-obj-$(CONFIG_POSIX) += event_notifier-posix.o aio-posix.o
block-obj-$(CONFIG_WIN32) += event_notifier-win32.o aio-win32.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
diff --git a/block/raw-posix-aio.h b/block/raw-posix-aio.h
index 6725135..c714367 100644
--- a/block/raw-posix-aio.h
+++ b/block/raw-posix-aio.h
@@ -27,14 +27,6 @@
#define QEMU_AIO_MISALIGNED 0x1000
-/* posix-aio-compat.c - thread pool based implementation */
-BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
- int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
- BlockDriverCompletionFunc *cb, void *opaque, int type);
-BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
- unsigned long int req, void *buf,
- BlockDriverCompletionFunc *cb, void *opaque);
-
/* linux-aio.c - Linux native implementation */
void *laio_init(void);
BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 9ae2c50..4d6d5df 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -27,6 +27,9 @@
#include "qemu-log.h"
#include "block_int.h"
#include "module.h"
+#include "trace.h"
+#include "thread-pool.h"
+#include "iov.h"
#include "block/raw-posix-aio.h"
#if defined(__APPLE__) && (__MACH__)
@@ -149,6 +152,20 @@ typedef struct BDRVRawReopenState {
static int fd_open(BlockDriverState *bs);
static int64_t raw_getlength(BlockDriverState *bs);
+typedef struct RawPosixAIOData {
+ BlockDriverState *bs;
+ int aio_fildes;
+ union {
+ struct iovec *aio_iov;
+ void *aio_ioctl_buf;
+ };
+ int aio_niov;
+ size_t aio_nbytes;
+#define aio_ioctl_cmd aio_nbytes /* for QEMU_AIO_IOCTL */
+ off_t aio_offset;
+ int aio_type;
+} RawPosixAIOData;
+
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
static int cdrom_reopen(BlockDriverState *bs);
#endif
@@ -426,6 +443,283 @@ static int qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov)
return 1;
}
+static ssize_t handle_aiocb_ioctl(RawPosixAIOData *aiocb)
+{
+ int ret;
+
+ ret = ioctl(aiocb->aio_fildes, aiocb->aio_ioctl_cmd, aiocb->aio_ioctl_buf);
+ if (ret == -1) {
+ return -errno;
+ }
+
+ /*
+ * This looks weird, but the aio code only considers a request
+ * successful if it has written the full number of bytes.
+ *
+ * Now we overload aio_nbytes as aio_ioctl_cmd for the ioctl command,
+ * so in fact we return the ioctl command here to make posix_aio_read()
+ * happy..
+ */
+ return aiocb->aio_nbytes;
+}
+
+static ssize_t handle_aiocb_flush(RawPosixAIOData *aiocb)
+{
+ int ret;
+
+ ret = qemu_fdatasync(aiocb->aio_fildes);
+ if (ret == -1) {
+ return -errno;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PREADV
+
+static bool preadv_present = true;
+
+static ssize_t
+qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset)
+{
+ return preadv(fd, iov, nr_iov, offset);
+}
+
+static ssize_t
+qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
+{
+ return pwritev(fd, iov, nr_iov, offset);
+}
+
+#else
+
+static bool preadv_present = false;
+
+static ssize_t
+qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset)
+{
+ return -ENOSYS;
+}
+
+static ssize_t
+qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
+{
+ return -ENOSYS;
+}
+
+#endif
+
+static ssize_t handle_aiocb_rw_vector(RawPosixAIOData *aiocb)
+{
+ ssize_t len;
+
+ do {
+ if (aiocb->aio_type & QEMU_AIO_WRITE)
+ len = qemu_pwritev(aiocb->aio_fildes,
+ aiocb->aio_iov,
+ aiocb->aio_niov,
+ aiocb->aio_offset);
+ else
+ len = qemu_preadv(aiocb->aio_fildes,
+ aiocb->aio_iov,
+ aiocb->aio_niov,
+ aiocb->aio_offset);
+ } while (len == -1 && errno == EINTR);
+
+ if (len == -1) {
+ return -errno;
+ }
+ return len;
+}
+
+/*
+ * Read/writes the data to/from a given linear buffer.
+ *
+ * Returns the number of bytes handles or -errno in case of an error. Short
+ * reads are only returned if the end of the file is reached.
+ */
+static ssize_t handle_aiocb_rw_linear(RawPosixAIOData *aiocb, char *buf)
+{
+ ssize_t offset = 0;
+ ssize_t len;
+
+ while (offset < aiocb->aio_nbytes) {
+ if (aiocb->aio_type & QEMU_AIO_WRITE) {
+ len = pwrite(aiocb->aio_fildes,
+ (const char *)buf + offset,
+ aiocb->aio_nbytes - offset,
+ aiocb->aio_offset + offset);
+ } else {
+ len = pread(aiocb->aio_fildes,
+ buf + offset,
+ aiocb->aio_nbytes - offset,
+ aiocb->aio_offset + offset);
+ }
+ if (len == -1 && errno == EINTR) {
+ continue;
+ } else if (len == -1) {
+ offset = -errno;
+ break;
+ } else if (len == 0) {
+ break;
+ }
+ offset += len;
+ }
+
+ return offset;
+}
+
+static ssize_t handle_aiocb_rw(RawPosixAIOData *aiocb)
+{
+ ssize_t nbytes;
+ char *buf;
+
+ if (!(aiocb->aio_type & QEMU_AIO_MISALIGNED)) {
+ /*
+ * If there is just a single buffer, and it is properly aligned
+ * we can just use plain pread/pwrite without any problems.
+ */
+ if (aiocb->aio_niov == 1) {
+ return handle_aiocb_rw_linear(aiocb, aiocb->aio_iov->iov_base);
+ }
+ /*
+ * We have more than one iovec, and all are properly aligned.
+ *
+ * Try preadv/pwritev first and fall back to linearizing the
+ * buffer if it's not supported.
+ */
+ if (preadv_present) {
+ nbytes = handle_aiocb_rw_vector(aiocb);
+ if (nbytes == aiocb->aio_nbytes ||
+ (nbytes < 0 && nbytes != -ENOSYS)) {
+ return nbytes;
+ }
+ preadv_present = false;
+ }
+
+ /*
+ * XXX(hch): short read/write. no easy way to handle the reminder
+ * using these interfaces. For now retry using plain
+ * pread/pwrite?
+ */
+ }
+
+ /*
+ * Ok, we have to do it the hard way, copy all segments into
+ * a single aligned buffer.
+ */
+ buf = qemu_blockalign(aiocb->bs, aiocb->aio_nbytes);
+ if (aiocb->aio_type & QEMU_AIO_WRITE) {
+ char *p = buf;
+ int i;
+
+ for (i = 0; i < aiocb->aio_niov; ++i) {
+ memcpy(p, aiocb->aio_iov[i].iov_base, aiocb->aio_iov[i].iov_len);
+ p += aiocb->aio_iov[i].iov_len;
+ }
+ }
+
+ nbytes = handle_aiocb_rw_linear(aiocb, buf);
+ if (!(aiocb->aio_type & QEMU_AIO_WRITE)) {
+ char *p = buf;
+ size_t count = aiocb->aio_nbytes, copy;
+ int i;
+
+ for (i = 0; i < aiocb->aio_niov && count; ++i) {
+ copy = count;
+ if (copy > aiocb->aio_iov[i].iov_len) {
+ copy = aiocb->aio_iov[i].iov_len;
+ }
+ memcpy(aiocb->aio_iov[i].iov_base, p, copy);
+ p += copy;
+ count -= copy;
+ }
+ }
+ qemu_vfree(buf);
+
+ return nbytes;
+}
+
+static int aio_worker(void *arg)
+{
+ RawPosixAIOData *aiocb = arg;
+ ssize_t ret = 0;
+
+ switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
+ case QEMU_AIO_READ:
+ ret = handle_aiocb_rw(aiocb);
+ if (ret >= 0 && ret < aiocb->aio_nbytes && aiocb->bs->growable) {
+ iov_memset(aiocb->aio_iov, aiocb->aio_niov, ret,
+ 0, aiocb->aio_nbytes - ret);
+
+ ret = aiocb->aio_nbytes;
+ }
+ if (ret == aiocb->aio_nbytes) {
+ ret = 0;
+ } else if (ret >= 0 && ret < aiocb->aio_nbytes) {
+ ret = -EINVAL;
+ }
+ break;
+ case QEMU_AIO_WRITE:
+ ret = handle_aiocb_rw(aiocb);
+ if (ret == aiocb->aio_nbytes) {
+ ret = 0;
+ } else if (ret >= 0 && ret < aiocb->aio_nbytes) {
+ ret = -EINVAL;
+ }
+ break;
+ case QEMU_AIO_FLUSH:
+ ret = handle_aiocb_flush(aiocb);
+ break;
+ case QEMU_AIO_IOCTL:
+ ret = handle_aiocb_ioctl(aiocb);
+ break;
+ default:
+ fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
+ ret = -EINVAL;
+ break;
+ }
+
+ g_slice_free(RawPosixAIOData, aiocb);
+ return ret;
+}
+
+static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque, int type)
+{
+ RawPosixAIOData *acb = g_slice_new(RawPosixAIOData);
+
+ acb->bs = bs;
+ acb->aio_type = type;
+ acb->aio_fildes = fd;
+
+ if (qiov) {
+ acb->aio_iov = qiov->iov;
+ acb->aio_niov = qiov->niov;
+ }
+ acb->aio_nbytes = nb_sectors * 512;
+ acb->aio_offset = sector_num * 512;
+
+ trace_paio_submit(acb, opaque, sector_num, nb_sectors, type);
+ return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
+}
+
+static BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
+ unsigned long int req, void *buf,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ RawPosixAIOData *acb = g_slice_new(RawPosixAIOData);
+
+ acb->bs = bs;
+ acb->aio_type = QEMU_AIO_IOCTL;
+ acb->aio_fildes = fd;
+ acb->aio_offset = 0;
+ acb->aio_ioctl_buf = buf;
+ acb->aio_ioctl_cmd = req;
+
+ return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
+}
+
static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type)
diff --git a/posix-aio-compat.c b/posix-aio-compat.c
deleted file mode 100644
index 4a1e3d3..0000000
--- a/posix-aio-compat.c
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * QEMU posix-aio emulation
- *
- * Copyright IBM, Corp. 2008
- *
- * Authors:
- * Anthony Liguori <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <errno.h>
-#include <time.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "qemu-queue.h"
-#include "osdep.h"
-#include "sysemu.h"
-#include "qemu-common.h"
-#include "trace.h"
-#include "thread-pool.h"
-#include "block_int.h"
-#include "iov.h"
-
-#include "block/raw-posix-aio.h"
-
-struct qemu_paiocb {
- BlockDriverAIOCB common;
- int aio_fildes;
- union {
- struct iovec *aio_iov;
- void *aio_ioctl_buf;
- };
- int aio_niov;
- size_t aio_nbytes;
-#define aio_ioctl_cmd aio_nbytes /* for QEMU_AIO_IOCTL */
- off_t aio_offset;
- int aio_type;
-};
-
-#ifdef CONFIG_PREADV
-static int preadv_present = 1;
-#else
-static int preadv_present = 0;
-#endif
-
-static ssize_t handle_aiocb_ioctl(struct qemu_paiocb *aiocb)
-{
- int ret;
-
- ret = ioctl(aiocb->aio_fildes, aiocb->aio_ioctl_cmd, aiocb->aio_ioctl_buf);
- if (ret == -1)
- return -errno;
-
- /*
- * This looks weird, but the aio code only considers a request
- * successful if it has written the full number of bytes.
- *
- * Now we overload aio_nbytes as aio_ioctl_cmd for the ioctl command,
- * so in fact we return the ioctl command here to make posix_aio_read()
- * happy..
- */
- return aiocb->aio_nbytes;
-}
-
-static ssize_t handle_aiocb_flush(struct qemu_paiocb *aiocb)
-{
- int ret;
-
- ret = qemu_fdatasync(aiocb->aio_fildes);
- if (ret == -1)
- return -errno;
- return 0;
-}
-
-#ifdef CONFIG_PREADV
-
-static ssize_t
-qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset)
-{
- return preadv(fd, iov, nr_iov, offset);
-}
-
-static ssize_t
-qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
-{
- return pwritev(fd, iov, nr_iov, offset);
-}
-
-#else
-
-static ssize_t
-qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset)
-{
- return -ENOSYS;
-}
-
-static ssize_t
-qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
-{
- return -ENOSYS;
-}
-
-#endif
-
-static ssize_t handle_aiocb_rw_vector(struct qemu_paiocb *aiocb)
-{
- ssize_t len;
-
- do {
- if (aiocb->aio_type & QEMU_AIO_WRITE)
- len = qemu_pwritev(aiocb->aio_fildes,
- aiocb->aio_iov,
- aiocb->aio_niov,
- aiocb->aio_offset);
- else
- len = qemu_preadv(aiocb->aio_fildes,
- aiocb->aio_iov,
- aiocb->aio_niov,
- aiocb->aio_offset);
- } while (len == -1 && errno == EINTR);
-
- if (len == -1)
- return -errno;
- return len;
-}
-
-/*
- * Read/writes the data to/from a given linear buffer.
- *
- * Returns the number of bytes handles or -errno in case of an error. Short
- * reads are only returned if the end of the file is reached.
- */
-static ssize_t handle_aiocb_rw_linear(struct qemu_paiocb *aiocb, char *buf)
-{
- ssize_t offset = 0;
- ssize_t len;
-
- while (offset < aiocb->aio_nbytes) {
- if (aiocb->aio_type & QEMU_AIO_WRITE)
- len = pwrite(aiocb->aio_fildes,
- (const char *)buf + offset,
- aiocb->aio_nbytes - offset,
- aiocb->aio_offset + offset);
- else
- len = pread(aiocb->aio_fildes,
- buf + offset,
- aiocb->aio_nbytes - offset,
- aiocb->aio_offset + offset);
-
- if (len == -1 && errno == EINTR)
- continue;
- else if (len == -1) {
- offset = -errno;
- break;
- } else if (len == 0)
- break;
-
- offset += len;
- }
-
- return offset;
-}
-
-static ssize_t handle_aiocb_rw(struct qemu_paiocb *aiocb)
-{
- ssize_t nbytes;
- char *buf;
-
- if (!(aiocb->aio_type & QEMU_AIO_MISALIGNED)) {
- /*
- * If there is just a single buffer, and it is properly aligned
- * we can just use plain pread/pwrite without any problems.
- */
- if (aiocb->aio_niov == 1)
- return handle_aiocb_rw_linear(aiocb, aiocb->aio_iov->iov_base);
-
- /*
- * We have more than one iovec, and all are properly aligned.
- *
- * Try preadv/pwritev first and fall back to linearizing the
- * buffer if it's not supported.
- */
- if (preadv_present) {
- nbytes = handle_aiocb_rw_vector(aiocb);
- if (nbytes == aiocb->aio_nbytes)
- return nbytes;
- if (nbytes < 0 && nbytes != -ENOSYS)
- return nbytes;
- preadv_present = 0;
- }
-
- /*
- * XXX(hch): short read/write. no easy way to handle the reminder
- * using these interfaces. For now retry using plain
- * pread/pwrite?
- */
- }
-
- /*
- * Ok, we have to do it the hard way, copy all segments into
- * a single aligned buffer.
- */
- buf = qemu_blockalign(aiocb->common.bs, aiocb->aio_nbytes);
- if (aiocb->aio_type & QEMU_AIO_WRITE) {
- char *p = buf;
- int i;
-
- for (i = 0; i < aiocb->aio_niov; ++i) {
- memcpy(p, aiocb->aio_iov[i].iov_base, aiocb->aio_iov[i].iov_len);
- p += aiocb->aio_iov[i].iov_len;
- }
- }
-
- nbytes = handle_aiocb_rw_linear(aiocb, buf);
- if (!(aiocb->aio_type & QEMU_AIO_WRITE)) {
- char *p = buf;
- size_t count = aiocb->aio_nbytes, copy;
- int i;
-
- for (i = 0; i < aiocb->aio_niov && count; ++i) {
- copy = count;
- if (copy > aiocb->aio_iov[i].iov_len)
- copy = aiocb->aio_iov[i].iov_len;
- memcpy(aiocb->aio_iov[i].iov_base, p, copy);
- p += copy;
- count -= copy;
- }
- }
- qemu_vfree(buf);
-
- return nbytes;
-}
-
-static int aio_worker(void *arg)
-{
- struct qemu_paiocb *aiocb = arg;
- ssize_t ret = 0;
-
- switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
- case QEMU_AIO_READ:
- ret = handle_aiocb_rw(aiocb);
- if (ret >= 0 && ret < aiocb->aio_nbytes && aiocb->common.bs->growable) {
- /* A short read means that we have reached EOF. Pad the buffer
- * with zeros for bytes after EOF. */
- iov_memset(aiocb->aio_iov, aiocb->aio_niov, ret,
- 0, aiocb->aio_nbytes - ret);
-
- ret = aiocb->aio_nbytes;
- }
- if (ret == aiocb->aio_nbytes) {
- ret = 0;
- } else if (ret >= 0 && ret < aiocb->aio_nbytes) {
- ret = -EINVAL;
- }
- break;
- case QEMU_AIO_WRITE:
- ret = handle_aiocb_rw(aiocb);
- if (ret == aiocb->aio_nbytes) {
- ret = 0;
- } else if (ret >= 0 && ret < aiocb->aio_nbytes) {
- ret = -EINVAL;
- }
- break;
- case QEMU_AIO_FLUSH:
- ret = handle_aiocb_flush(aiocb);
- break;
- case QEMU_AIO_IOCTL:
- ret = handle_aiocb_ioctl(aiocb);
- break;
- default:
- fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
- ret = -EINVAL;
- break;
- }
-
- qemu_aio_release(aiocb);
- return ret;
-}
-
-static AIOPool raw_aio_pool = {
- .aiocb_size = sizeof(struct qemu_paiocb),
-};
-
-BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
- int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
- BlockDriverCompletionFunc *cb, void *opaque, int type)
-{
- struct qemu_paiocb *acb;
-
- acb = qemu_aio_get(&raw_aio_pool, bs, cb, opaque);
- acb->aio_type = type;
- acb->aio_fildes = fd;
-
- if (qiov) {
- acb->aio_iov = qiov->iov;
- acb->aio_niov = qiov->niov;
- }
- acb->aio_nbytes = nb_sectors * 512;
- acb->aio_offset = sector_num * 512;
-
- trace_paio_submit(acb, opaque, sector_num, nb_sectors, type);
- return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
-}
-
-BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
- unsigned long int req, void *buf,
- BlockDriverCompletionFunc *cb, void *opaque)
-{
- struct qemu_paiocb *acb;
-
- acb = qemu_aio_get(&raw_aio_pool, bs, cb, opaque);
- acb->aio_type = QEMU_AIO_IOCTL;
- acb->aio_fildes = fd;
- acb->aio_offset = 0;
- acb->aio_ioctl_buf = buf;
- acb->aio_ioctl_cmd = req;
-
- return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
-}
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 35/39] raw: merge posix-aio-compat.c into block/raw-posix.c
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 35/39] raw: merge posix-aio-compat.c into block/raw-posix.c Paolo Bonzini
@ 2012-11-02 15:00 ` Peter Maydell
0 siblings, 0 replies; 62+ messages in thread
From: Peter Maydell @ 2012-11-02 15:00 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: aliguori, qemu-devel, stefanha
On 31 October 2012 16:30, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Making the qemu_paiocb specific to raw devices will let us access members
> of the BDRVRawState arbitrarily.
>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
clang now warns about an unused function:
CC block/raw-posix.o
block/raw-posix.c:707:26: warning: unused function 'paio_ioctl'
[-Wunused-function]
static BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
^
1 warning generated.
because the only use of paio_ioctl() is inside a #if defined(__linux__)
guard and it's 'static' now.
-- PMM
^ permalink raw reply [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 36/39] raw-posix: rename raw-posix-aio.h, hide unavailable prototypes
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (34 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 35/39] raw: merge posix-aio-compat.c into block/raw-posix.c Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 37/39] raw-win32: add emulated AIO support Paolo Bonzini
` (3 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
block/{raw-posix-aio.h => raw-aio.h} | 10 ++++++----
block/raw-posix.c | 2 +-
linux-aio.c | 2 +-
3 file modificati, 8 inserzioni(+), 6 rimozioni(-)
rename block/{raw-posix-aio.h => raw-aio.h} (86%)
diff --git a/block/raw-posix-aio.h b/block/raw-aio.h
similarity index 86%
rename from block/raw-posix-aio.h
rename to block/raw-aio.h
index c714367..b3bb073 100644
--- a/block/raw-posix-aio.h
+++ b/block/raw-aio.h
@@ -1,5 +1,5 @@
/*
- * QEMU Posix block I/O backend AIO support
+ * Declarations for AIO in the raw protocol
*
* Copyright IBM, Corp. 2008
*
@@ -12,8 +12,8 @@
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
-#ifndef QEMU_RAW_POSIX_AIO_H
-#define QEMU_RAW_POSIX_AIO_H
+#ifndef QEMU_RAW_AIO_H
+#define QEMU_RAW_AIO_H
/* AIO request types */
#define QEMU_AIO_READ 0x0001
@@ -28,9 +28,11 @@
/* linux-aio.c - Linux native implementation */
+#ifdef CONFIG_LINUX_AIO
void *laio_init(void);
BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type);
+#endif
-#endif /* QEMU_RAW_POSIX_AIO_H */
+#endif /* QEMU_RAW_AIO_H */
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 4d6d5df..f2f0404 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -30,7 +30,7 @@
#include "trace.h"
#include "thread-pool.h"
#include "iov.h"
-#include "block/raw-posix-aio.h"
+#include "raw-aio.h"
#if defined(__APPLE__) && (__MACH__)
#include <paths.h>
diff --git a/linux-aio.c b/linux-aio.c
index d1afb46..6ca984d 100644
--- a/linux-aio.c
+++ b/linux-aio.c
@@ -10,7 +10,7 @@
#include "qemu-common.h"
#include "qemu-aio.h"
#include "qemu-queue.h"
-#include "block/raw-posix-aio.h"
+#include "block/raw-aio.h"
#include "event_notifier.h"
#include <libaio.h>
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 37/39] raw-win32: add emulated AIO support
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (35 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 36/39] raw-posix: rename raw-posix-aio.h, hide unavailable prototypes Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 38/39] raw-posix: move linux-aio.c to block/ Paolo Bonzini
` (2 subsequent siblings)
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
block/raw-win32.c | 187 ++++++++++++++++++++++++++++++++++++++++--------------
1 file modificato, 138 inserzioni(+), 49 rimozioni(-)
diff --git a/block/raw-win32.c b/block/raw-win32.c
index 78c8306..ffd86e3 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -25,6 +25,10 @@
#include "qemu-timer.h"
#include "block_int.h"
#include "module.h"
+#include "raw-aio.h"
+#include "trace.h"
+#include "thread-pool.h"
+#include "iov.h"
#include <windows.h>
#include <winioctl.h>
@@ -32,12 +36,127 @@
#define FTYPE_CD 1
#define FTYPE_HARDDISK 2
+typedef struct RawWin32AIOData {
+ BlockDriverState *bs;
+ HANDLE hfile;
+ struct iovec *aio_iov;
+ int aio_niov;
+ size_t aio_nbytes;
+ off64_t aio_offset;
+ int aio_type;
+} RawWin32AIOData;
+
typedef struct BDRVRawState {
HANDLE hfile;
int type;
char drive_path[16]; /* format: "d:\" */
} BDRVRawState;
+/*
+ * Read/writes the data to/from a given linear buffer.
+ *
+ * Returns the number of bytes handles or -errno in case of an error. Short
+ * reads are only returned if the end of the file is reached.
+ */
+static size_t handle_aiocb_rw(RawWin32AIOData *aiocb)
+{
+ size_t offset = 0;
+ int i;
+
+ for (i = 0; i < aiocb->aio_niov; i++) {
+ OVERLAPPED ov;
+ DWORD ret, ret_count, len;
+
+ memset(&ov, 0, sizeof(ov));
+ ov.Offset = (aiocb->aio_offset + offset);
+ ov.OffsetHigh = (aiocb->aio_offset + offset) >> 32;
+ len = aiocb->aio_iov[i].iov_len;
+ if (aiocb->aio_type & QEMU_AIO_WRITE) {
+ ret = WriteFile(aiocb->hfile, aiocb->aio_iov[i].iov_base,
+ len, &ret_count, &ov);
+ } else {
+ ret = ReadFile(aiocb->hfile, aiocb->aio_iov[i].iov_base,
+ len, &ret_count, &ov);
+ }
+ if (!ret) {
+ ret_count = 0;
+ }
+ if (ret_count != len) {
+ break;
+ }
+ offset += len;
+ }
+
+ return offset;
+}
+
+static int aio_worker(void *arg)
+{
+ RawWin32AIOData *aiocb = arg;
+ ssize_t ret = 0;
+ size_t count;
+
+ switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
+ case QEMU_AIO_READ:
+ count = handle_aiocb_rw(aiocb);
+ if (count < aiocb->aio_nbytes && aiocb->bs->growable) {
+ /* A short read means that we have reached EOF. Pad the buffer
+ * with zeros for bytes after EOF. */
+ iov_memset(aiocb->aio_iov, aiocb->aio_niov, count,
+ 0, aiocb->aio_nbytes - count);
+
+ count = aiocb->aio_nbytes;
+ }
+ if (count == aiocb->aio_nbytes) {
+ ret = 0;
+ } else {
+ ret = -EINVAL;
+ }
+ break;
+ case QEMU_AIO_WRITE:
+ count = handle_aiocb_rw(aiocb);
+ if (count == aiocb->aio_nbytes) {
+ count = 0;
+ } else {
+ count = -EINVAL;
+ }
+ break;
+ case QEMU_AIO_FLUSH:
+ if (!FlushFileBuffers(aiocb->hfile)) {
+ return -EIO;
+ }
+ break;
+ default:
+ fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
+ ret = -EINVAL;
+ break;
+ }
+
+ g_slice_free(RawWin32AIOData, aiocb);
+ return ret;
+}
+
+static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque, int type)
+{
+ RawWin32AIOData *acb = g_slice_new(RawWin32AIOData);
+
+ acb->bs = bs;
+ acb->hfile = hfile;
+ acb->aio_type = type;
+
+ if (qiov) {
+ acb->aio_iov = qiov->iov;
+ acb->aio_niov = qiov->niov;
+ }
+ acb->aio_nbytes = nb_sectors * 512;
+ acb->aio_offset = sector_num * 512;
+
+ trace_paio_submit(acb, opaque, sector_num, nb_sectors, type);
+ return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
+}
+
int qemu_ftruncate64(int fd, int64_t length)
{
LARGE_INTEGER li;
@@ -117,59 +236,29 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
return 0;
}
-static int raw_read(BlockDriverState *bs, int64_t sector_num,
- uint8_t *buf, int nb_sectors)
+static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
{
BDRVRawState *s = bs->opaque;
- OVERLAPPED ov;
- DWORD ret_count;
- int ret;
- int64_t offset = sector_num * 512;
- int count = nb_sectors * 512;
-
- memset(&ov, 0, sizeof(ov));
- ov.Offset = offset;
- ov.OffsetHigh = offset >> 32;
- ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
- if (!ret)
- return ret_count;
- if (ret_count == count)
- ret_count = 0;
- return ret_count;
+ return paio_submit(bs, s->hfile, sector_num, qiov, nb_sectors,
+ cb, opaque, QEMU_AIO_READ);
}
-static int raw_write(BlockDriverState *bs, int64_t sector_num,
- const uint8_t *buf, int nb_sectors)
+static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
{
BDRVRawState *s = bs->opaque;
- OVERLAPPED ov;
- DWORD ret_count;
- int ret;
- int64_t offset = sector_num * 512;
- int count = nb_sectors * 512;
-
- memset(&ov, 0, sizeof(ov));
- ov.Offset = offset;
- ov.OffsetHigh = offset >> 32;
- ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
- if (!ret)
- return ret_count;
- if (ret_count == count)
- ret_count = 0;
- return ret_count;
+ return paio_submit(bs, s->hfile, sector_num, qiov, nb_sectors,
+ cb, opaque, QEMU_AIO_WRITE);
}
-static int raw_flush(BlockDriverState *bs)
+static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque)
{
BDRVRawState *s = bs->opaque;
- int ret;
-
- ret = FlushFileBuffers(s->hfile);
- if (ret == 0) {
- return -EIO;
- }
-
- return 0;
+ return paio_submit(bs, s->hfile, 0, NULL, 0, cb, opaque, QEMU_AIO_FLUSH);
}
static void raw_close(BlockDriverState *bs)
@@ -290,9 +379,9 @@ static BlockDriver bdrv_file = {
.bdrv_close = raw_close,
.bdrv_create = raw_create,
- .bdrv_read = raw_read,
- .bdrv_write = raw_write,
- .bdrv_co_flush_to_disk = raw_flush,
+ .bdrv_aio_readv = raw_aio_readv,
+ .bdrv_aio_writev = raw_aio_writev,
+ .bdrv_aio_flush = raw_aio_flush,
.bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength,
@@ -413,9 +502,9 @@ static BlockDriver bdrv_host_device = {
.bdrv_close = raw_close,
.bdrv_has_zero_init = hdev_has_zero_init,
- .bdrv_read = raw_read,
- .bdrv_write = raw_write,
- .bdrv_co_flush_to_disk = raw_flush,
+ .bdrv_aio_readv = raw_aio_readv,
+ .bdrv_aio_writev = raw_aio_writev,
+ .bdrv_aio_flush = raw_aio_flush,
.bdrv_getlength = raw_getlength,
.bdrv_get_allocated_file_size
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 38/39] raw-posix: move linux-aio.c to block/
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (36 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 37/39] raw-win32: add emulated AIO support Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 39/39] raw-win32: implement native asynchronous I/O Paolo Bonzini
2012-11-01 19:33 ` [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Anthony Liguori
39 siblings, 0 replies; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
Makefile.objs | 1 -
block/Makefile.objs | 1 +
linux-aio.c => block/linux-aio.c | 0
3 file modificati, 1 inserzione(+). 1 rimozione(-)
rename linux-aio.c => block/linux-aio.c (100%)
diff --git a/Makefile.objs b/Makefile.objs
index 35c2355..2b5427e 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -47,7 +47,6 @@ block-obj-y += thread-pool.o qemu-progress.o qemu-sockets.o uri.o notify.o
block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y)
block-obj-$(CONFIG_POSIX) += event_notifier-posix.o aio-posix.o
block-obj-$(CONFIG_WIN32) += event_notifier-win32.o aio-win32.o
-block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
block-obj-y += block/
block-obj-y += $(qapi-obj-y) qapi-types.o qapi-visit.o
diff --git a/block/Makefile.objs b/block/Makefile.objs
index 684765b..771d341 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -5,6 +5,7 @@ block-obj-y += qed-check.o
block-obj-y += parallels.o blkdebug.o blkverify.o
block-obj-$(CONFIG_WIN32) += raw-win32.o
block-obj-$(CONFIG_POSIX) += raw-posix.o
+block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
ifeq ($(CONFIG_POSIX),y)
block-obj-y += nbd.o sheepdog.o
diff --git a/linux-aio.c b/block/linux-aio.c
similarity index 100%
rename from linux-aio.c
rename to block/linux-aio.c
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [Qemu-devel] [PATCH v2 39/39] raw-win32: implement native asynchronous I/O
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (37 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 38/39] raw-posix: move linux-aio.c to block/ Paolo Bonzini
@ 2012-10-31 15:30 ` Paolo Bonzini
2012-11-21 13:20 ` Jan Kiszka
2012-11-01 19:33 ` [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Anthony Liguori
39 siblings, 1 reply; 62+ messages in thread
From: Paolo Bonzini @ 2012-10-31 15:30 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, stefanha
With the new support for EventNotifiers in the AIO event loop, we
can hook a completion port to every opened file and use asynchronous
I/O on them.
Wine's support is extremely inefficient, also because it really does
the I/O synchronously on regular files. (!) But it works, and it is
good to keep the Win32 and POSIX ports as similar as possible.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
block/Makefile.objs | 2 +-
block/raw-aio.h | 10 +++
block/raw-win32.c | 42 ++++++++--
block/win32-aio.c | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++++
4 file modificati, 274 inserzioni(+), 6 rimozioni(-)
create mode 100644 block/win32-aio.c
diff --git a/block/Makefile.objs b/block/Makefile.objs
index 771d341..30ef6ae 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -3,7 +3,7 @@ block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-c
block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
block-obj-y += qed-check.o
block-obj-y += parallels.o blkdebug.o blkverify.o
-block-obj-$(CONFIG_WIN32) += raw-win32.o
+block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
block-obj-$(CONFIG_POSIX) += raw-posix.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
diff --git a/block/raw-aio.h b/block/raw-aio.h
index b3bb073..e77f361 100644
--- a/block/raw-aio.h
+++ b/block/raw-aio.h
@@ -35,4 +35,14 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
BlockDriverCompletionFunc *cb, void *opaque, int type);
#endif
+#ifdef _WIN32
+typedef struct QEMUWin32AIOState QEMUWin32AIOState;
+QEMUWin32AIOState *win32_aio_init(void);
+int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile);
+BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
+ QEMUWin32AIOState *aio, HANDLE hfile,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque, int type);
+#endif
+
#endif /* QEMU_RAW_AIO_H */
diff --git a/block/raw-win32.c b/block/raw-win32.c
index ffd86e3..0c05c58 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -36,6 +36,8 @@
#define FTYPE_CD 1
#define FTYPE_HARDDISK 2
+static QEMUWin32AIOState *aio;
+
typedef struct RawWin32AIOData {
BlockDriverState *bs;
HANDLE hfile;
@@ -50,6 +52,7 @@ typedef struct BDRVRawState {
HANDLE hfile;
int type;
char drive_path[16]; /* format: "d:\" */
+ QEMUWin32AIOState *aio;
} BDRVRawState;
/*
@@ -208,6 +211,9 @@ static void raw_parse_flags(int flags, int *access_flags, DWORD *overlapped)
}
*overlapped = FILE_ATTRIBUTE_NORMAL;
+ if (flags & BDRV_O_NATIVE_AIO) {
+ *overlapped |= FILE_FLAG_OVERLAPPED;
+ }
if (flags & BDRV_O_NOCACHE) {
*overlapped |= FILE_FLAG_NO_BUFFERING;
}
@@ -222,6 +228,13 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
s->type = FTYPE_FILE;
raw_parse_flags(flags, &access_flags, &overlapped);
+
+ if ((flags & BDRV_O_NATIVE_AIO) && aio == NULL) {
+ aio = win32_aio_init();
+ if (aio == NULL) {
+ return -EINVAL;
+ }
+ }
s->hfile = CreateFile(filename, access_flags,
FILE_SHARE_READ, NULL,
@@ -231,7 +244,16 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
if (err == ERROR_ACCESS_DENIED)
return -EACCES;
- return -1;
+ return -EINVAL;
+ }
+
+ if (flags & BDRV_O_NATIVE_AIO) {
+ int ret = win32_aio_attach(aio, s->hfile);
+ if (ret < 0) {
+ CloseHandle(s->hfile);
+ return ret;
+ }
+ s->aio = aio;
}
return 0;
}
@@ -241,8 +263,13 @@ static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
BDRVRawState *s = bs->opaque;
- return paio_submit(bs, s->hfile, sector_num, qiov, nb_sectors,
- cb, opaque, QEMU_AIO_READ);
+ if (s->aio) {
+ return win32_aio_submit(bs, s->aio, s->hfile, sector_num, qiov,
+ nb_sectors, cb, opaque, QEMU_AIO_READ);
+ } else {
+ return paio_submit(bs, s->hfile, sector_num, qiov, nb_sectors,
+ cb, opaque, QEMU_AIO_READ);
+ }
}
static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
@@ -250,8 +277,13 @@ static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
BDRVRawState *s = bs->opaque;
- return paio_submit(bs, s->hfile, sector_num, qiov, nb_sectors,
- cb, opaque, QEMU_AIO_WRITE);
+ if (s->aio) {
+ return win32_aio_submit(bs, s->aio, s->hfile, sector_num, qiov,
+ nb_sectors, cb, opaque, QEMU_AIO_WRITE);
+ } else {
+ return paio_submit(bs, s->hfile, sector_num, qiov, nb_sectors,
+ cb, opaque, QEMU_AIO_WRITE);
+ }
}
static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
diff --git a/block/win32-aio.c b/block/win32-aio.c
new file mode 100644
index 0000000..c34dc73
--- /dev/null
+++ b/block/win32-aio.c
@@ -0,0 +1,226 @@
+/*
+ * Block driver for RAW files (win32)
+ *
+ * Copyright (c) 2006 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 "qemu-common.h"
+#include "qemu-timer.h"
+#include "block_int.h"
+#include "module.h"
+#include "qemu-common.h"
+#include "qemu-aio.h"
+#include "raw-aio.h"
+#include "event_notifier.h"
+#include <windows.h>
+#include <winioctl.h>
+
+#define FTYPE_FILE 0
+#define FTYPE_CD 1
+#define FTYPE_HARDDISK 2
+
+struct QEMUWin32AIOState {
+ HANDLE hIOCP;
+ EventNotifier e;
+ int count;
+};
+
+typedef struct QEMUWin32AIOCB {
+ BlockDriverAIOCB common;
+ struct QEMUWin32AIOState *ctx;
+ int nbytes;
+ OVERLAPPED ov;
+ QEMUIOVector *qiov;
+ void *buf;
+ bool is_read;
+ bool is_linear;
+} QEMUWin32AIOCB;
+
+/*
+ * Completes an AIO request (calls the callback and frees the ACB).
+ */
+static void win32_aio_process_completion(QEMUWin32AIOState *s,
+ QEMUWin32AIOCB *waiocb, DWORD count)
+{
+ int ret;
+ s->count--;
+
+ if (waiocb->ov.Internal != 0) {
+ ret = -EIO;
+ } else {
+ ret = 0;
+ if (count < waiocb->nbytes) {
+ /* Short reads mean EOF, pad with zeros. */
+ if (waiocb->is_read) {
+ qemu_iovec_memset(waiocb->qiov, count, 0,
+ waiocb->qiov->size - count);
+ } else {
+ ret = -EINVAL;
+ }
+ }
+ }
+
+ if (!waiocb->is_linear) {
+ if (ret == 0 && waiocb->is_read) {
+ QEMUIOVector *qiov = waiocb->qiov;
+ char *p = waiocb->buf;
+ int i;
+
+ for (i = 0; i < qiov->niov; ++i) {
+ memcpy(p, qiov->iov[i].iov_base, qiov->iov[i].iov_len);
+ p += qiov->iov[i].iov_len;
+ }
+ g_free(waiocb->buf);
+ }
+ }
+
+
+ waiocb->common.cb(waiocb->common.opaque, ret);
+ qemu_aio_release(waiocb);
+}
+
+static void win32_aio_completion_cb(EventNotifier *e)
+{
+ QEMUWin32AIOState *s = container_of(e, QEMUWin32AIOState, e);
+ DWORD count;
+ ULONG_PTR key;
+ OVERLAPPED *ov;
+
+ event_notifier_test_and_clear(&s->e);
+ while (GetQueuedCompletionStatus(s->hIOCP, &count, &key, &ov, 0)) {
+ QEMUWin32AIOCB *waiocb = container_of(ov, QEMUWin32AIOCB, ov);
+
+ win32_aio_process_completion(s, waiocb, count);
+ }
+}
+
+static int win32_aio_flush_cb(EventNotifier *e)
+{
+ QEMUWin32AIOState *s = container_of(e, QEMUWin32AIOState, e);
+
+ return (s->count > 0) ? 1 : 0;
+}
+
+static void win32_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+ QEMUWin32AIOCB *waiocb = (QEMUWin32AIOCB *)blockacb;
+
+ /*
+ * CancelIoEx is only supported in Vista and newer. For now, just
+ * wait for completion.
+ */
+ while (!HasOverlappedIoCompleted(&waiocb->ov)) {
+ qemu_aio_wait();
+ }
+}
+
+static AIOPool win32_aio_pool = {
+ .aiocb_size = sizeof(QEMUWin32AIOCB),
+ .cancel = win32_aio_cancel,
+};
+
+BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
+ QEMUWin32AIOState *aio, HANDLE hfile,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque, int type)
+{
+ struct QEMUWin32AIOCB *waiocb;
+ uint64_t offset = sector_num * 512;
+ DWORD rc;
+
+ waiocb = qemu_aio_get(&win32_aio_pool, bs, cb, opaque);
+ waiocb->nbytes = nb_sectors * 512;
+ waiocb->qiov = qiov;
+ waiocb->is_read = (type == QEMU_AIO_READ);
+
+ if (qiov->niov > 1) {
+ waiocb->buf = qemu_blockalign(bs, qiov->size);
+ if (type & QEMU_AIO_WRITE) {
+ char *p = waiocb->buf;
+ int i;
+
+ for (i = 0; i < qiov->niov; ++i) {
+ memcpy(p, qiov->iov[i].iov_base, qiov->iov[i].iov_len);
+ p += qiov->iov[i].iov_len;
+ }
+ }
+ waiocb->is_linear = false;
+ } else {
+ waiocb->buf = qiov->iov[0].iov_base;
+ waiocb->is_linear = true;
+ }
+
+ waiocb->ov = (OVERLAPPED) {
+ .Offset = (DWORD) offset,
+ .OffsetHigh = (DWORD) (offset >> 32),
+ .hEvent = event_notifier_get_handle(&aio->e)
+ };
+ aio->count++;
+
+ if (type & QEMU_AIO_READ) {
+ rc = ReadFile(hfile, waiocb->buf, waiocb->nbytes, NULL, &waiocb->ov);
+ } else {
+ rc = WriteFile(hfile, waiocb->buf, waiocb->nbytes, NULL, &waiocb->ov);
+ }
+ if(rc == 0 && GetLastError() != ERROR_IO_PENDING) {
+ goto out_dec_count;
+ }
+ return &waiocb->common;
+
+out_dec_count:
+ aio->count--;
+ qemu_aio_release(waiocb);
+ return NULL;
+}
+
+int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile)
+{
+ if (CreateIoCompletionPort(hfile, aio->hIOCP, (ULONG_PTR) 0, 0) == NULL) {
+ return -EINVAL;
+ } else {
+ return 0;
+ }
+}
+
+QEMUWin32AIOState *win32_aio_init(void)
+{
+ QEMUWin32AIOState *s;
+
+ s = g_malloc0(sizeof(*s));
+ if (event_notifier_init(&s->e, false) < 0) {
+ goto out_free_state;
+ }
+
+ s->hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
+ if (s->hIOCP == NULL) {
+ goto out_close_efd;
+ }
+
+ qemu_aio_set_event_notifier(&s->e, win32_aio_completion_cb,
+ win32_aio_flush_cb);
+
+ return s;
+
+out_close_efd:
+ event_notifier_cleanup(&s->e);
+out_free_state:
+ g_free(s);
+ return NULL;
+}
--
1.7.12.1
^ permalink raw reply related [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 39/39] raw-win32: implement native asynchronous I/O
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 39/39] raw-win32: implement native asynchronous I/O Paolo Bonzini
@ 2012-11-21 13:20 ` Jan Kiszka
2012-11-21 13:25 ` Paolo Bonzini
0 siblings, 1 reply; 62+ messages in thread
From: Jan Kiszka @ 2012-11-21 13:20 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: aliguori, qemu-devel, stefanha
On 2012-10-31 16:30, Paolo Bonzini wrote:
> With the new support for EventNotifiers in the AIO event loop, we
> can hook a completion port to every opened file and use asynchronous
> I/O on them.
>
> Wine's support is extremely inefficient, also because it really does
> the I/O synchronously on regular files. (!) But it works, and it is
> good to keep the Win32 and POSIX ports as similar as possible.
>
I'm seeing a regression with this patch when cross-compiling with
mingw32 for Win7. QEMU is stuck while booting a versatilepb guest that
accesses the block layer via pflash. Enabling tracing "fixes" the issue,
of course...
Are there any patches flying around that are supposed to resolve this?
Jan
--
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 39/39] raw-win32: implement native asynchronous I/O
2012-11-21 13:20 ` Jan Kiszka
@ 2012-11-21 13:25 ` Paolo Bonzini
2012-11-21 13:27 ` Jan Kiszka
0 siblings, 1 reply; 62+ messages in thread
From: Paolo Bonzini @ 2012-11-21 13:25 UTC (permalink / raw)
To: Jan Kiszka; +Cc: aliguori, qemu-devel, stefanha
Il 21/11/2012 14:20, Jan Kiszka ha scritto:
> I'm seeing a regression with this patch when cross-compiling with
> mingw32 for Win7. QEMU is stuck while booting a versatilepb guest that
> accesses the block layer via pflash. Enabling tracing "fixes" the issue,
> of course...
>
> Are there any patches flying around that are supposed to resolve this?
No. Is this with aio=native or aio=threads?
Paolo
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 39/39] raw-win32: implement native asynchronous I/O
2012-11-21 13:25 ` Paolo Bonzini
@ 2012-11-21 13:27 ` Jan Kiszka
2012-11-21 13:33 ` Paolo Bonzini
0 siblings, 1 reply; 62+ messages in thread
From: Jan Kiszka @ 2012-11-21 13:27 UTC (permalink / raw)
To: Paolo Bonzini
Cc: aliguori@us.ibm.com, qemu-devel@nongnu.org, stefanha@redhat.com
On 2012-11-21 14:25, Paolo Bonzini wrote:
> Il 21/11/2012 14:20, Jan Kiszka ha scritto:
>> I'm seeing a regression with this patch when cross-compiling with
>> mingw32 for Win7. QEMU is stuck while booting a versatilepb guest that
>> accesses the block layer via pflash. Enabling tracing "fixes" the issue,
>> of course...
>>
>> Are there any patches flying around that are supposed to resolve this?
>
> No. Is this with aio=native or aio=threads?
aio=<default> - whatever that is on win32.
Jan
--
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 39/39] raw-win32: implement native asynchronous I/O
2012-11-21 13:27 ` Jan Kiszka
@ 2012-11-21 13:33 ` Paolo Bonzini
2012-11-21 13:38 ` Jan Kiszka
0 siblings, 1 reply; 62+ messages in thread
From: Paolo Bonzini @ 2012-11-21 13:33 UTC (permalink / raw)
To: Jan Kiszka
Cc: aliguori@us.ibm.com, qemu-devel@nongnu.org, stefanha@redhat.com
Il 21/11/2012 14:27, Jan Kiszka ha scritto:
>>> >> Are there any patches flying around that are supposed to resolve this?
>> >
>> > No. Is this with aio=native or aio=threads?
> aio=<default> - whatever that is on win32.
That's aio=threads, just like POSIX. I'm curious (but not too
optimistic) whether aio=native fixes it.
Anyhow, do you have a reproducer that I can download?
Paolo
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 39/39] raw-win32: implement native asynchronous I/O
2012-11-21 13:33 ` Paolo Bonzini
@ 2012-11-21 13:38 ` Jan Kiszka
2012-11-22 13:34 ` Jan Kiszka
0 siblings, 1 reply; 62+ messages in thread
From: Jan Kiszka @ 2012-11-21 13:38 UTC (permalink / raw)
To: Paolo Bonzini
Cc: aliguori@us.ibm.com, qemu-devel@nongnu.org, stefanha@redhat.com
On 2012-11-21 14:33, Paolo Bonzini wrote:
> Il 21/11/2012 14:27, Jan Kiszka ha scritto:
>>>>>> Are there any patches flying around that are supposed to resolve this?
>>>>
>>>> No. Is this with aio=native or aio=threads?
>> aio=<default> - whatever that is on win32.
>
> That's aio=threads, just like POSIX. I'm curious (but not too
> optimistic) whether aio=native fixes it.
Just tried, and it actually makes no difference.
>
> Anyhow, do you have a reproducer that I can download?
Unfortunately, not at this point. Have to check, maybe I can trip the
image to the bare Linux guest.
Jan
--
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 39/39] raw-win32: implement native asynchronous I/O
2012-11-21 13:38 ` Jan Kiszka
@ 2012-11-22 13:34 ` Jan Kiszka
2012-11-22 15:16 ` Paolo Bonzini
0 siblings, 1 reply; 62+ messages in thread
From: Jan Kiszka @ 2012-11-22 13:34 UTC (permalink / raw)
To: Paolo Bonzini
Cc: aliguori@us.ibm.com, qemu-devel@nongnu.org, stefanha@redhat.com
On 2012-11-21 14:38, Jan Kiszka wrote:
> On 2012-11-21 14:33, Paolo Bonzini wrote:
>> Il 21/11/2012 14:27, Jan Kiszka ha scritto:
>>>>>>> Are there any patches flying around that are supposed to resolve this?
>>>>>
>>>>> No. Is this with aio=native or aio=threads?
>>> aio=<default> - whatever that is on win32.
>>
>> That's aio=threads, just like POSIX. I'm curious (but not too
>> optimistic) whether aio=native fixes it.
>
> Just tried, and it actually makes no difference.
>
>>
>> Anyhow, do you have a reproducer that I can download?
>
> Unfortunately, not at this point. Have to check, maybe I can trip the
> image to the bare Linux guest.
Maybe this helps:
=>0 0xf77c242e __kernel_vsyscall+0xe() in [vdso].so (0x0519df88)
1 0xf761f10b __libc_read+0x4a() in libpthread.so.0 (0x0519df88)
2 0x7bc78c98 in ntdll (+0x68c97) (0x0519df88)
3 0x7bc7b0a3 in ntdll (+0x6b0a2) (0x0519e1b8)
4 0x7bc7b195 NtWaitForMultipleObjects+0x54() in ntdll (0x0519e1e8)
5 0x7b86de9f WaitForMultipleObjectsEx+0xee() in kernel32 (0x0519e338)
6 0x7b86df1a WaitForMultipleObjects+0x39() in kernel32 (0x0519e368)
7 0x0040301b aio_poll+0x16a(ctx=0x157610, blocking=<is not available>) [/data/qemu/aio-win32.c:178] in qemu-system-arm (0x00000001)
8 0x004feec3 qemu_aio_wait+0x22() [/data/qemu/main-loop.c:442] in qemu-system-arm (0x0105bdec)
9 0x00417166 bdrv_rw_co+0xa5(bs=0x159648, sector_num=<internal error>, buf="¹¸ÿ¦
", nb_sectors=0x4, is_write=true) [/data/qemu/block.c:1997] in qemu-system-arm (0x0105bdec)
10 0x00495544 in qemu-system-arm (+0x95543) (0x0105bdec)
11 0x0049592a pflash_write+0x3b9(pfl=0xd6f16e0, offset=<internal error>, value=0x98f7fb1d, width=0x4, be=0) [/data/qemu/hw/pflash_cfi01.c:405] in qemu-system-arm (0x0105bdec)
12 0x00618a7e io_mem_write+0xed(mr=0xd6f2a48, addr=0x105bdec, val=0x98f7fb1d, size=0x4) [/data/qemu/memory.c:911] in qemu-system-arm (0x00000004)
13 0x0064088c helper_stl_mmu+0x2fb(env=0x15e268, addr=0xca05bdec, val=0x98f7fb1d, mmu_idx=0) [/data/qemu/softmmu_template.h:231] in qemu-system-arm (0x3700001e)
14 0x02136637 (0x0015e268)
It's the VCPU thread stuck in aio_poll, holding the BQL, blocking the
iothread this way as well. Is there some race that prevents we receive
the proper IO completion signal? Any states I should check?
Jan
--
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 39/39] raw-win32: implement native asynchronous I/O
2012-11-22 13:34 ` Jan Kiszka
@ 2012-11-22 15:16 ` Paolo Bonzini
2012-11-22 15:53 ` Jan Kiszka
0 siblings, 1 reply; 62+ messages in thread
From: Paolo Bonzini @ 2012-11-22 15:16 UTC (permalink / raw)
To: Jan Kiszka
Cc: aliguori@us.ibm.com, qemu-devel@nongnu.org, stefanha@redhat.com
Il 22/11/2012 14:34, Jan Kiszka ha scritto:
>
> =>0 0xf77c242e __kernel_vsyscall+0xe() in [vdso].so (0x0519df88)
> 1 0xf761f10b __libc_read+0x4a() in libpthread.so.0 (0x0519df88)
> 2 0x7bc78c98 in ntdll (+0x68c97) (0x0519df88)
> 3 0x7bc7b0a3 in ntdll (+0x6b0a2) (0x0519e1b8)
> 4 0x7bc7b195 NtWaitForMultipleObjects+0x54() in ntdll (0x0519e1e8)
> 5 0x7b86de9f WaitForMultipleObjectsEx+0xee() in kernel32 (0x0519e338)
> 6 0x7b86df1a WaitForMultipleObjects+0x39() in kernel32 (0x0519e368)
> 7 0x0040301b aio_poll+0x16a(ctx=0x157610, blocking=<is not available>) [/data/qemu/aio-win32.c:178] in qemu-system-arm (0x00000001)
> 8 0x004feec3 qemu_aio_wait+0x22() [/data/qemu/main-loop.c:442] in qemu-system-arm (0x0105bdec)
> 9 0x00417166 bdrv_rw_co+0xa5(bs=0x159648, sector_num=<internal error>, buf="¹¸ÿ¦
> ", nb_sectors=0x4, is_write=true) [/data/qemu/block.c:1997] in qemu-system-arm (0x0105bdec)
> 10 0x00495544 in qemu-system-arm (+0x95543) (0x0105bdec)
> 11 0x0049592a pflash_write+0x3b9(pfl=0xd6f16e0, offset=<internal error>, value=0x98f7fb1d, width=0x4, be=0) [/data/qemu/hw/pflash_cfi01.c:405] in qemu-system-arm (0x0105bdec)
> 12 0x00618a7e io_mem_write+0xed(mr=0xd6f2a48, addr=0x105bdec, val=0x98f7fb1d, size=0x4) [/data/qemu/memory.c:911] in qemu-system-arm (0x00000004)
> 13 0x0064088c helper_stl_mmu+0x2fb(env=0x15e268, addr=0xca05bdec, val=0x98f7fb1d, mmu_idx=0) [/data/qemu/softmmu_template.h:231] in qemu-system-arm (0x3700001e)
> 14 0x02136637 (0x0015e268)
>
> It's the VCPU thread stuck in aio_poll, holding the BQL, blocking the
> iothread this way as well. Is there some race that prevents we receive
> the proper IO completion signal? Any states I should check?
Ah, so it wasn't fixed by the TLS change?
Instead of tracing, can you try adding printfs in aio_worker
(block/raw-win32.c), and also in thread_pool_active and
event_notifier_ready (thread-pool.c)?
This patch can help gathering debug output, it will place it into a
console window.
diff --git a/vl.c b/vl.c
index c8e9c78..5398178 100644
--- a/vl.c
+++ b/vl.c
@@ -3531,6 +3531,10 @@ int main(int argc, char **argv, char **envp)
}
loc_set_none();
+ AllocConsole();
+ freopen("CONIN$", "rb", stdin);
+ freopen("CONOUT$", "wb", stdout);
+ freopen("CONOUT$", "wb", stderr);
if (qemu_init_main_loop()) {
fprintf(stderr, "qemu_init_main_loop failed\n");
exit(1);
Paolo
^ permalink raw reply related [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PATCH v2 39/39] raw-win32: implement native asynchronous I/O
2012-11-22 15:16 ` Paolo Bonzini
@ 2012-11-22 15:53 ` Jan Kiszka
0 siblings, 0 replies; 62+ messages in thread
From: Jan Kiszka @ 2012-11-22 15:53 UTC (permalink / raw)
To: Paolo Bonzini
Cc: aliguori@us.ibm.com, qemu-devel@nongnu.org, stefanha@redhat.com
On 2012-11-22 16:16, Paolo Bonzini wrote:
> Il 22/11/2012 14:34, Jan Kiszka ha scritto:
>>
>> =>0 0xf77c242e __kernel_vsyscall+0xe() in [vdso].so (0x0519df88)
>> 1 0xf761f10b __libc_read+0x4a() in libpthread.so.0 (0x0519df88)
>> 2 0x7bc78c98 in ntdll (+0x68c97) (0x0519df88)
>> 3 0x7bc7b0a3 in ntdll (+0x6b0a2) (0x0519e1b8)
>> 4 0x7bc7b195 NtWaitForMultipleObjects+0x54() in ntdll (0x0519e1e8)
>> 5 0x7b86de9f WaitForMultipleObjectsEx+0xee() in kernel32 (0x0519e338)
>> 6 0x7b86df1a WaitForMultipleObjects+0x39() in kernel32 (0x0519e368)
>> 7 0x0040301b aio_poll+0x16a(ctx=0x157610, blocking=<is not available>) [/data/qemu/aio-win32.c:178] in qemu-system-arm (0x00000001)
>> 8 0x004feec3 qemu_aio_wait+0x22() [/data/qemu/main-loop.c:442] in qemu-system-arm (0x0105bdec)
>> 9 0x00417166 bdrv_rw_co+0xa5(bs=0x159648, sector_num=<internal error>, buf="¹¸ÿ¦
>> ", nb_sectors=0x4, is_write=true) [/data/qemu/block.c:1997] in qemu-system-arm (0x0105bdec)
>> 10 0x00495544 in qemu-system-arm (+0x95543) (0x0105bdec)
>> 11 0x0049592a pflash_write+0x3b9(pfl=0xd6f16e0, offset=<internal error>, value=0x98f7fb1d, width=0x4, be=0) [/data/qemu/hw/pflash_cfi01.c:405] in qemu-system-arm (0x0105bdec)
>> 12 0x00618a7e io_mem_write+0xed(mr=0xd6f2a48, addr=0x105bdec, val=0x98f7fb1d, size=0x4) [/data/qemu/memory.c:911] in qemu-system-arm (0x00000004)
>> 13 0x0064088c helper_stl_mmu+0x2fb(env=0x15e268, addr=0xca05bdec, val=0x98f7fb1d, mmu_idx=0) [/data/qemu/softmmu_template.h:231] in qemu-system-arm (0x3700001e)
>> 14 0x02136637 (0x0015e268)
>>
>> It's the VCPU thread stuck in aio_poll, holding the BQL, blocking the
>> iothread this way as well. Is there some race that prevents we receive
>> the proper IO completion signal? Any states I should check?
>
> Ah, so it wasn't fixed by the TLS change?
This version was built with my more recent opensuse mingw toolchain,
thus isn't affected by the TLS issue.
>
> Instead of tracing, can you try adding printfs in aio_worker
> (block/raw-win32.c), and also in thread_pool_active and
> event_notifier_ready (thread-pool.c)?
>
> This patch can help gathering debug output, it will place it into a
> console window.
>
> diff --git a/vl.c b/vl.c
> index c8e9c78..5398178 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -3531,6 +3531,10 @@ int main(int argc, char **argv, char **envp)
> }
> loc_set_none();
>
> + AllocConsole();
> + freopen("CONIN$", "rb", stdin);
> + freopen("CONOUT$", "wb", stdout);
> + freopen("CONOUT$", "wb", stderr);
> if (qemu_init_main_loop()) {
> fprintf(stderr, "qemu_init_main_loop failed\n");
> exit(1);
Ok, will dig into this.
Thanks,
Jan
--
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO
2012-10-31 15:30 [Qemu-devel] [PULL v2 00/39] AioContext, thread pool, Win32 AIO Paolo Bonzini
` (38 preceding siblings ...)
2012-10-31 15:30 ` [Qemu-devel] [PATCH v2 39/39] raw-win32: implement native asynchronous I/O Paolo Bonzini
@ 2012-11-01 19:33 ` Anthony Liguori
39 siblings, 0 replies; 62+ messages in thread
From: Anthony Liguori @ 2012-11-01 19:33 UTC (permalink / raw)
To: Paolo Bonzini, qemu-devel; +Cc: stefanha
Paolo Bonzini <pbonzini@redhat.com> writes:
> The following changes since commit aee0bf7d8d7564f8f2c40e4501695c492b7dd8d1:
>
> tap-win32: stubs to fix win32 build (2012-10-30 19:18:53 +0000)
>
> are available in the git repository at:
>
> git://github.com/bonzini/qemu.git threadpool
>
> for you to fetch changes up to f563a5d7a820424756f358e747238f03e866838a:
>
> Merge remote-tracking branch 'origin/master' into threadpool (2012-10-31 10:42:51 +0100)
>
> Patches 1 to 12 eliminate the dependencies of qemu-tool.c on the main loop
> and AIO infrastructure. Otherwise the build rules for vscclient, tests
> and qemu-ga become too hairy. Patches 13 to 30 introduce AioContext
> and a new portable AIO API based on EventNotifier. Patches 31 to 38
> introduce a generic threadpool that replaces posix-aio-compat.c.
> Patch 39 introduces support for Win32 native AIO. (As usual, Win32
> bits are mostly there as a testbed for the flexibility of the API).
>
> The patches are based in the remote branch on a known-good commit for
> Win32 (because TCG is a bit broken in master). Thus there is a merge
> commit at the top to fix the trivial conflicts between patch 1 and the
> later introduction of iov_copy.
>
> Paolo
>
Pulled. Thanks.
Regards,
Anthony Liguori
> ----------------------------------------------------------------
>
> Paolo Bonzini (39):
> janitor: move iovector functions out of cutils.c
> build: move cutils.o and qemu-timer-common.o to oslib-obj-y
> compiler: use weak aliases to provide default definitions
> sockets: use weak aliases instead of qemu-tool.c
> fdsets: use weak aliases instead of qemu-tool.c/qemu-user.c
> iohandler: add weak alias in qemu-sockets.c, for qemu-ga
> win32: add weak version of qemu_fd_register
> qemu-timer: make initialization functions idempotent
> main-loop: unify qemu_init_main_loop between QEMU and tools
> qemu-tool: do not depend on qemu-timer.c
> build: opts-visitor is not really part of QAPI
> build: do not include main loop where it is not actually used
> event_notifier: add Win32 implementation
> event_notifier: enable it to use pipes
> vl: init main loop earlier
> aio: change qemu_aio_set_fd_handler to return void
> aio: provide platform-independent API
> aio: introduce AioContext, move bottom halves there
> aio: add I/O handlers to the AioContext interface
> aio: test node->deleted before calling io_flush
> aio: add non-blocking variant of aio_wait
> aio: prepare for introducing GSource-based dispatch
> aio: add Win32 implementation
> aio: make AioContexts GSources
> aio: add aio_notify
> aio: call aio_notify after setting I/O handlers
> main-loop: use GSource to poll AIO file descriptors
> main-loop: use aio_notify for qemu_notify_event
> aio: clean up now-unused functions
> linux-aio: use event notifiers
> qemu-thread: add QemuSemaphore
> aio: add generic thread-pool facility
> threadpool: do not take lock in event_notifier_ready
> block: switch posix-aio-compat to threadpool
> raw: merge posix-aio-compat.c into block/raw-posix.c
> raw-posix: rename raw-posix-aio.h, hide unavailable prototypes
> raw-win32: add emulated AIO support
> raw-posix: move linux-aio.c to block/
> raw-win32: implement native asynchronous I/O
>
> Makefile | 7 +-
> Makefile.objs | 22 +-
> aio-posix.c | 268 ++++++++++++++
> aio-win32.c | 215 +++++++++++
> aio.c | 194 ----------
> arch_init.h | 2 +-
> async.c | 118 +++++-
> block/Makefile.objs | 9 +-
> linux-aio.c => block/linux-aio.c | 52 ++-
> block/{raw-posix-aio.h => raw-aio.h} | 29 +-
> block/raw-posix.c | 308 +++++++++++++++-
> block/raw-win32.c | 221 +++++++++---
> block/win32-aio.c | 226 ++++++++++++
> compiler.h | 11 +-
> cutils.c | 108 ------
> event_notifier-posix.c | 120 +++++++
> event_notifier-win32.c | 59 +++
> event_notifier.c | 67 ----
> event_notifier.h | 20 +-
> hw/hw.h | 1 +
> iohandler.c | 1 +
> iov.c | 103 ++++++
> main-loop.c | 157 +++-----
> main-loop.h | 66 +---
> osdep.c | 30 ++
> oslib-posix.c | 31 --
> oslib-win32.c | 5 +
> posix-aio-compat.c | 679 -----------------------------------
> qapi/Makefile.objs | 4 +-
> qemu-aio.h | 206 ++++++++++-
> qemu-char.h | 1 +
> qemu-common.h | 3 +-
> qemu-coroutine-lock.c | 2 +-
> qemu-os-win32.h | 1 -
> qemu-sockets.c | 18 +
> qemu-thread-posix.c | 80 +++++
> qemu-thread-posix.h | 5 +
> qemu-thread-win32.c | 35 ++
> qemu-thread-win32.h | 4 +
> qemu-thread.h | 7 +
> qemu-timer.c | 12 +-
> qemu-tool.c | 35 +-
> qemu-user.c | 20 --
> qmp.c | 3 +-
> tests/Makefile | 8 +-
> thread-pool.c | 289 +++++++++++++++
> thread-pool.h | 34 ++
> trace-events | 5 +
> vl.c | 17 +-
> 49 file modificati, 2429 inserzioni(+), 1489 rimozioni(-)
> create mode 100644 aio-posix.c
> create mode 100644 aio-win32.c
> delete mode 100644 aio.c
> rename linux-aio.c => block/linux-aio.c (82%)
> rename block/{raw-posix-aio.h => raw-aio.h} (71%)
> create mode 100644 block/win32-aio.c
> create mode 100644 event_notifier-posix.c
> create mode 100644 event_notifier-win32.c
> delete mode 100644 event_notifier.c
> delete mode 100644 posix-aio-compat.c
> create mode 100644 thread-pool.c
> create mode 100644 thread-pool.h
> --
> 1.7.12.1
^ permalink raw reply [flat|nested] 62+ messages in thread