>From 9b67defc5eacb9254a8140a4daa52949f0fe60e2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 26 Sep 2011 10:59:46 +0200 Subject: [PATCH 1/2] qemu-io: use main_loop_wait This will let timers run during aio_read and aio_write commands, though not during synchronous commands. Not-tested-by: Paolo Bonzini Signed-off-by: Paolo Bonzini --- cmd.c | 10 +++++----- qemu-io.c | 8 +++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cmd.c b/cmd.c index 0806e18..7ffbb71 100644 --- a/cmd.c +++ b/cmd.c @@ -25,6 +25,7 @@ #include "cmd.h" #include "qemu-aio.h" +#include "main-loop.h" #define _(x) x /* not gettext support yet */ @@ -146,7 +147,7 @@ static void prep_fetchline(void *opaque) { int *fetchable = opaque; - qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL); + qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL); *fetchable= 1; } @@ -193,12 +194,11 @@ void command_loop(void) if (!prompted) { printf("%s", get_prompt()); fflush(stdout); - qemu_aio_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, NULL, - NULL, &fetchable); + qemu_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, &fetchable); prompted = 1; } - qemu_aio_wait(); + main_loop_wait(false); if (!fetchable) { continue; @@ -221,7 +221,7 @@ void command_loop(void) prompted = 0; fetchable = 0; } - qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL); + qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL); } /* from libxcmd/input.c */ diff --git a/qemu-io.c b/qemu-io.c index ffa62fb..6e1bee3 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -15,6 +15,7 @@ #include #include "qemu-common.h" +#include "main-loop.h" #include "block_int.h" #include "cmd.h" @@ -249,7 +250,7 @@ static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total) bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9, aio_rw_done, &async_ret); while (async_ret == NOT_DONE) { - qemu_aio_wait(); + main_loop_wait(false); } *total = qiov->size; @@ -263,7 +264,7 @@ static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total) bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9, aio_rw_done, &async_ret); while (async_ret == NOT_DONE) { - qemu_aio_wait(); + main_loop_wait(false); } *total = qiov->size; @@ -306,7 +307,7 @@ static int do_aio_multiwrite(BlockRequest* reqs, int num_reqs, int *total) } while (async_ret.num_done < num_reqs) { - qemu_aio_wait(); + main_loop_wait(false); } return async_ret.error < 0 ? async_ret.error : 1; @@ -1793,6 +1794,7 @@ int main(int argc, char **argv) exit(1); } + qemu_init_main_loop(); bdrv_init(); /* initialize commands */ -- 1.7.7.1 >From ac2958b0992dcd155ab76885cac044a9fec5cc06 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Oct 2011 12:20:44 +0200 Subject: [PATCH 2/2] qemu-img: run commands in coroutine context The new function qemu_coroutine_schedule is in qemu-coroutine-lock.c since it's where the other dependencies on the main loop reside. Not-tested-by: Paolo Bonzini Signed-off-by: Paolo Bonzini --- main-loop.h | 20 ++++++-------------- qemu-coroutine-lock.c | 24 ++++++++++++++++++++++++ qemu-coroutine.h | 8 ++++++++ qemu-img.c | 40 ++++++++++++++++++++++++++++++++-------- 4 files changed, 70 insertions(+), 22 deletions(-) diff --git a/main-loop.h b/main-loop.h index f971013..4e99485 100644 --- a/main-loop.h +++ b/main-loop.h @@ -59,24 +59,16 @@ int qemu_init_main_loop(void); * It is sometimes useful to put a whole program in a coroutine. In this * case, the coroutine actually should be started from within the main loop, * so that the main loop can run whenever the coroutine yields. To do this, - * you can use a bottom half to enter the coroutine as soon as the main loop - * starts: + * you can use qemu_coroutine_schedule. * - * void enter_co_bh(void *opaque) { - * QEMUCoroutine *co = opaque; - * qemu_coroutine_enter(co, NULL); - * } - * - * ... - * QEMUCoroutine *co = qemu_coroutine_create(coroutine_entry); - * QEMUBH *start_bh = qemu_bh_new(enter_co_bh, co); - * qemu_bh_schedule(start_bh); - * while (...) { + * int ret = -1; + * Coroutine *co = qemu_coroutine_create(coroutine_entry); + * qemu_init_main_loop(); + * qemu_coroutine_schedule(co, &ret); + * while (ret == -1) { * main_loop_wait(false); * } * - * (In the future we may provide a wrapper for this). - * * @nonblocking: Whether the caller should block until an event occurs. */ int main_loop_wait(int nonblocking); diff --git a/qemu-coroutine-lock.c b/qemu-coroutine-lock.c index 26ad76b..45a2fc2 100644 --- a/qemu-coroutine-lock.c +++ b/qemu-coroutine-lock.c @@ -169,3 +169,27 @@ void qemu_co_rwlock_wrlock(CoRwlock *lock) } lock->writer = true; } + +typedef struct { + QEMUBH *bh; + Coroutine *co; + void *opaque; +} CoroutineBHArgs; + +static void qemu_coroutine_schedule_bh(void *opaque) +{ + CoroutineBHArgs args = *(CoroutineBHArgs *)opaque; + g_free(opaque); + qemu_bh_delete(args.bh); + qemu_coroutine_enter(args.co, args.opaque); +} + +void qemu_coroutine_schedule(Coroutine *co, void *opaque) +{ + CoroutineBHArgs *args = g_malloc(sizeof(CoroutineBHArgs)); + args->bh = qemu_bh_new(qemu_coroutine_schedule_bh, args); + args->co = co; + args->opaque = opaque; + qemu_bh_schedule(args->bh); +} + diff --git a/qemu-coroutine.h b/qemu-coroutine.h index 8a55fe1..8cdef58 100644 --- a/qemu-coroutine.h +++ b/qemu-coroutine.h @@ -199,4 +199,12 @@ void qemu_co_rwlock_wrlock(CoRwlock *lock); */ void qemu_co_rwlock_unlock(CoRwlock *lock); +/** + * Transfer control to a coroutine from a bottom half + * + * The opaque argument is passed as the argument to the entry point when + * entering the coroutine for the first time. It is subsequently ignored. + */ +void qemu_coroutine_schedule(Coroutine *coroutine, void *opaque); + #endif /* QEMU_COROUTINE_H */ diff --git a/qemu-img.c b/qemu-img.c index 01cc0d3..2123476 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -24,6 +24,8 @@ #include "qemu-common.h" #include "qemu-option.h" #include "qemu-error.h" +#include "qemu-coroutine.h" +#include "main-loop.h" #include "osdep.h" #include "sysemu.h" #include "block_int.h" @@ -1674,27 +1676,49 @@ static const img_cmd_t img_cmds[] = { { NULL, NULL, }, }; -int main(int argc, char **argv) +typedef struct { + int argc; + char **argv; + int ret; +} MainArgs; + +static void main_co_entry(void *opaque) { + MainArgs *args = opaque; const img_cmd_t *cmd; const char *cmdname; - error_set_progname(argv[0]); - - bdrv_init(); - if (argc < 2) + if (args->argc < 2) help(); - cmdname = argv[1]; - argc--; argv++; + cmdname = args->argv[1]; + args->argc--; args->argv++; /* find the command */ for(cmd = img_cmds; cmd->name != NULL; cmd++) { if (!strcmp(cmdname, cmd->name)) { - return cmd->handler(argc, argv); + args->ret = cmd->handler(args->argc, args->argv); + return; } } /* not found */ help(); + args->ret = 0; +} + +#define NOT_DONE 0x7fffffff + +int main(int argc, char **argv) +{ + error_set_progname(argv[0]); + MainArgs args = { .argc = argc, .argv = argv, .ret = NOT_DONE }; + Coroutine *co = qemu_coroutine_create(main_co_entry); + + qemu_init_main_loop(); + bdrv_init(); + qemu_coroutine_schedule(co, &args); + while (args.ret == NOT_DONE) { + main_loop_wait(false); + } return 0; } -- 1.7.7.1