diff mbox

[2/2] qemu-io: check registered fds in command_loop()

Message ID 1276624421-23999-3-git-send-email-morita.kazutaka@lab.ntt.co.jp
State New
Headers show

Commit Message

MORITA Kazutaka June 15, 2010, 5:53 p.m. UTC
Some block drivers use an aio handler and do I/O completion routines
in it.  However, the handler is not invoked if we only do
aio_read/write, because registered fds are not checked at all.

This patch registers a command processing function as a fd handler to
STDIO, and calls qemu_aio_wait() in command_loop().  Any other
handlers can be invoked when user input is idle.

Signed-off-by: MORITA Kazutaka <morita.kazutaka@lab.ntt.co.jp>
---
 cmd.c |   53 +++++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 39 insertions(+), 14 deletions(-)

Comments

Kevin Wolf June 16, 2010, 11:24 a.m. UTC | #1
Am 15.06.2010 19:53, schrieb MORITA Kazutaka:
> Some block drivers use an aio handler and do I/O completion routines
> in it.  However, the handler is not invoked if we only do
> aio_read/write, because registered fds are not checked at all.
> 
> This patch registers a command processing function as a fd handler to
> STDIO, and calls qemu_aio_wait() in command_loop().  Any other
> handlers can be invoked when user input is idle.
> 
> Signed-off-by: MORITA Kazutaka <morita.kazutaka@lab.ntt.co.jp>

This patch is much nicer than I would have expected it to be!

Thanks, applied to the block branch.

Kevin
Kevin Wolf June 18, 2010, 4:21 p.m. UTC | #2
Am 15.06.2010 19:53, schrieb MORITA Kazutaka:
> Some block drivers use an aio handler and do I/O completion routines
> in it.  However, the handler is not invoked if we only do
> aio_read/write, because registered fds are not checked at all.
> 
> This patch registers a command processing function as a fd handler to
> STDIO, and calls qemu_aio_wait() in command_loop().  Any other
> handlers can be invoked when user input is idle.
> 
> Signed-off-by: MORITA Kazutaka <morita.kazutaka@lab.ntt.co.jp>

This breaks qemu-iotests. The reason is that synchronous requests get
out of order. Previously, do_aio_readv/writev waited until the request
was completed, and only afterwards the next command was read from stdio.
Now the next command can start during the qemu_aio_wait() that
do_aio_readv/writev uses internally to wait.

So we either need to deregister the fd handler while a command is
running, or (more cleanly) have an async_context_push/pop for any
command except aio_*.

Kevin
diff mbox

Patch

diff --git a/cmd.c b/cmd.c
index 460df92..2b66e24 100644
--- a/cmd.c
+++ b/cmd.c
@@ -24,6 +24,7 @@ 
 #include <getopt.h>
 
 #include "cmd.h"
+#include "qemu-aio.h"
 
 #define _(x)	x	/* not gettext support yet */
 
@@ -149,6 +150,37 @@  add_args_command(
 	args_func = af;
 }
 
+static char *get_prompt(void);
+
+static void do_command(void *opaque)
+{
+	int		c;
+	int *done = opaque;
+	char		*input;
+	char		**v;
+	const cmdinfo_t	*ct;
+
+	if ((input = fetchline()) == NULL) {
+		*done = 1;
+		return;
+	}
+	v = breakline(input, &c);
+	if (c) {
+		ct = find_command(v[0]);
+		if (ct)
+			*done = command(ct, c, v);
+		else
+			fprintf(stderr, _("command \"%s\" not found\n"),
+				v[0]);
+	}
+	doneline(input, v);
+
+	if (*done == 0) {
+		printf("%s", get_prompt());
+		fflush(stdout);
+	}
+}
+
 void
 command_loop(void)
 {
@@ -186,20 +218,15 @@  command_loop(void)
 		free(cmdline);
 		return;
 	}
+
+	printf("%s", get_prompt());
+	fflush(stdout);
+
+	qemu_aio_set_fd_handler(STDIN_FILENO, do_command, NULL, NULL, NULL, &done);
 	while (!done) {
-		if ((input = fetchline()) == NULL)
-			break;
-		v = breakline(input, &c);
-		if (c) {
-			ct = find_command(v[0]);
-			if (ct)
-				done = command(ct, c, v);
-			else
-				fprintf(stderr, _("command \"%s\" not found\n"),
-					v[0]);
-		}
-		doneline(input, v);
+		qemu_aio_wait();
 	}
+	qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
 }
 
 /* from libxcmd/input.c */
@@ -270,8 +297,6 @@  fetchline(void)
 
 	if (!line)
 		return NULL;
-	printf("%s", get_prompt());
-	fflush(stdout);
 again:
 	if (!fgets(line, MAXREADLINESZ, stdin)) {
 		if (errno == EINTR)