aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS1
-rw-r--r--block/io.c3
-rw-r--r--hw/ide/core.c17
-rw-r--r--hw/ide/macio.c2
-rw-r--r--include/qemu/coroutine_int.h1
-rw-r--r--include/qemu/queue.h8
-rw-r--r--linux-user/xtensa/syscall.h0
-rw-r--r--target/xtensa/core-dc232b.c6
-rw-r--r--target/xtensa/core-dc232b/gdb-config.inc.c (renamed from target/xtensa/core-dc232b/gdb-config.c)0
-rw-r--r--target/xtensa/core-dc232b/xtensa-modules.inc.c (renamed from target/xtensa/core-dc232b/xtensa-modules.c)0
-rw-r--r--target/xtensa/core-dc233c.c4
-rw-r--r--target/xtensa/core-dc233c/gdb-config.inc.c (renamed from target/xtensa/core-dc233c/gdb-config.c)0
-rw-r--r--target/xtensa/core-dc233c/xtensa-modules.inc.c (renamed from target/xtensa/core-dc233c/xtensa-modules.c)0
-rw-r--r--target/xtensa/core-de212.c4
-rw-r--r--target/xtensa/core-de212/gdb-config.inc.c (renamed from target/xtensa/core-de212/gdb-config.c)0
-rw-r--r--target/xtensa/core-de212/xtensa-modules.inc.c (renamed from target/xtensa/core-de212/xtensa-modules.c)0
-rw-r--r--target/xtensa/core-fsf.c2
-rw-r--r--target/xtensa/core-fsf/xtensa-modules.inc.c (renamed from target/xtensa/core-fsf/xtensa-modules.c)0
-rw-r--r--target/xtensa/core-sample_controller.c4
-rw-r--r--target/xtensa/core-sample_controller/gdb-config.inc.c (renamed from target/xtensa/core-sample_controller/gdb-config.c)0
-rw-r--r--target/xtensa/core-sample_controller/xtensa-modules.inc.c (renamed from target/xtensa/core-sample_controller/xtensa-modules.c)0
-rwxr-xr-xtarget/xtensa/import_core.sh9
-rw-r--r--tests/tcg/xtensa/Makefile2
-rw-r--r--tests/test-aio.c63
-rw-r--r--util/qemu-coroutine-lock.c34
-rw-r--r--util/qemu-coroutine.c94
26 files changed, 138 insertions, 116 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 6fa36c7a2d..24b70169bc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1351,6 +1351,7 @@ F: util/aio-*.c
F: block/io.c
F: migration/block*
F: include/block/aio.h
+F: include/block/aio-wait.h
F: scripts/qemugdb/aio.py
T: git git://github.com/stefanha/qemu.git block
diff --git a/block/io.c b/block/io.c
index 2b09c656d0..bd9a19a9c4 100644
--- a/block/io.c
+++ b/block/io.c
@@ -249,8 +249,7 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
BdrvCoDrainData data;
/* Calling bdrv_drain() from a BH ensures the current coroutine yields and
- * other coroutines run if they were queued from
- * qemu_co_queue_run_restart(). */
+ * other coroutines run if they were queued by aio_co_enter(). */
assert(qemu_in_coroutine());
data = (BdrvCoDrainData) {
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 139c843514..866c659498 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -402,7 +402,6 @@ typedef struct TrimAIOCB {
QEMUIOVector *qiov;
BlockAIOCB *aiocb;
int i, j;
- bool is_invalid;
} TrimAIOCB;
static void trim_aio_cancel(BlockAIOCB *acb)
@@ -430,11 +429,8 @@ static void ide_trim_bh_cb(void *opaque)
{
TrimAIOCB *iocb = opaque;
- if (iocb->is_invalid) {
- ide_dma_error(iocb->s);
- } else {
- iocb->common.cb(iocb->common.opaque, iocb->ret);
- }
+ iocb->common.cb(iocb->common.opaque, iocb->ret);
+
qemu_bh_delete(iocb->bh);
iocb->bh = NULL;
qemu_aio_unref(iocb);
@@ -462,7 +458,7 @@ static void ide_issue_trim_cb(void *opaque, int ret)
}
if (!ide_sect_range_ok(s, sector, count)) {
- iocb->is_invalid = true;
+ iocb->ret = -EINVAL;
goto done;
}
@@ -502,7 +498,6 @@ BlockAIOCB *ide_issue_trim(
iocb->qiov = qiov;
iocb->i = -1;
iocb->j = 0;
- iocb->is_invalid = false;
ide_issue_trim_cb(iocb, 0);
return &iocb->common;
}
@@ -848,6 +843,12 @@ static void ide_dma_cb(void *opaque, int ret)
if (ret == -ECANCELED) {
return;
}
+
+ if (ret == -EINVAL) {
+ ide_dma_error(s);
+ return;
+ }
+
if (ret < 0) {
if (ide_handle_rw_error(s, -ret, ide_dma_cmd_to_retry(s->dma_cmd))) {
s->bus->dma->aiocb = NULL;
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index 2e043ef1ea..d3a85cba3b 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -187,7 +187,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
break;
case IDE_DMA_TRIM:
s->bus->dma->aiocb = dma_blk_io(blk_get_aio_context(s->blk), &s->sg,
- offset, 0x1, ide_issue_trim, s->blk,
+ offset, 0x1, ide_issue_trim, s,
pmac_ide_transfer_cb, io,
DMA_DIRECTION_TO_DEVICE);
break;
diff --git a/include/qemu/coroutine_int.h b/include/qemu/coroutine_int.h
index 59e8406398..bd6b0468e1 100644
--- a/include/qemu/coroutine_int.h
+++ b/include/qemu/coroutine_int.h
@@ -68,6 +68,5 @@ Coroutine *qemu_coroutine_new(void);
void qemu_coroutine_delete(Coroutine *co);
CoroutineAction qemu_coroutine_switch(Coroutine *from, Coroutine *to,
CoroutineAction action);
-void coroutine_fn qemu_co_queue_run_restart(Coroutine *co);
#endif
diff --git a/include/qemu/queue.h b/include/qemu/queue.h
index aa270d2b38..59fd1203a1 100644
--- a/include/qemu/queue.h
+++ b/include/qemu/queue.h
@@ -324,6 +324,14 @@ struct { \
} \
} while (/*CONSTCOND*/0)
+#define QSIMPLEQ_PREPEND(head1, head2) do { \
+ if (!QSIMPLEQ_EMPTY((head2))) { \
+ *(head2)->sqh_last = (head1)->sqh_first; \
+ (head1)->sqh_first = (head2)->sqh_first; \
+ QSIMPLEQ_INIT((head2)); \
+ } \
+} while (/*CONSTCOND*/0)
+
#define QSIMPLEQ_LAST(head, type, field) \
(QSIMPLEQ_EMPTY((head)) ? \
NULL : \
diff --git a/linux-user/xtensa/syscall.h b/linux-user/xtensa/syscall.h
deleted file mode 100644
index e69de29bb2..0000000000
--- a/linux-user/xtensa/syscall.h
+++ /dev/null
diff --git a/target/xtensa/core-dc232b.c b/target/xtensa/core-dc232b.c
index fe80582df4..7331eeea2f 100644
--- a/target/xtensa/core-dc232b.c
+++ b/target/xtensa/core-dc232b.c
@@ -35,7 +35,7 @@
#include "overlay_tool.h"
#define xtensa_modules xtensa_modules_dc232b
-#include "core-dc232b/xtensa-modules.c"
+#include "core-dc232b/xtensa-modules.inc.c"
static XtensaConfig dc232b __attribute__((unused)) = {
.name = "dc232b",
@@ -43,11 +43,11 @@ static XtensaConfig dc232b __attribute__((unused)) = {
.num_regs = 120,
.num_core_regs = 52,
.reg = {
-#include "core-dc232b/gdb-config.c"
+#include "core-dc232b/gdb-config.inc.c"
}
},
.isa_internal = &xtensa_modules,
- .clock_freq_khz = 10000,
+ .clock_freq_khz = (NANOSECONDS_PER_SECOND / 64) / 1000,
DEFAULT_SECTIONS
};
diff --git a/target/xtensa/core-dc232b/gdb-config.c b/target/xtensa/core-dc232b/gdb-config.inc.c
index 13aba5edec..13aba5edec 100644
--- a/target/xtensa/core-dc232b/gdb-config.c
+++ b/target/xtensa/core-dc232b/gdb-config.inc.c
diff --git a/target/xtensa/core-dc232b/xtensa-modules.c b/target/xtensa/core-dc232b/xtensa-modules.inc.c
index d322c3f52a..d322c3f52a 100644
--- a/target/xtensa/core-dc232b/xtensa-modules.c
+++ b/target/xtensa/core-dc232b/xtensa-modules.inc.c
diff --git a/target/xtensa/core-dc233c.c b/target/xtensa/core-dc233c.c
index 00301c28a2..8296e6fa10 100644
--- a/target/xtensa/core-dc233c.c
+++ b/target/xtensa/core-dc233c.c
@@ -36,7 +36,7 @@
#include "overlay_tool.h"
#define xtensa_modules xtensa_modules_dc233c
-#include "core-dc233c/xtensa-modules.c"
+#include "core-dc233c/xtensa-modules.inc.c"
static XtensaConfig dc233c __attribute__((unused)) = {
.name = "dc233c",
@@ -44,7 +44,7 @@ static XtensaConfig dc233c __attribute__((unused)) = {
.num_regs = 121,
.num_core_regs = 52,
.reg = {
-#include "core-dc233c/gdb-config.c"
+#include "core-dc233c/gdb-config.inc.c"
}
},
.isa_internal = &xtensa_modules,
diff --git a/target/xtensa/core-dc233c/gdb-config.c b/target/xtensa/core-dc233c/gdb-config.inc.c
index b632341b28..b632341b28 100644
--- a/target/xtensa/core-dc233c/gdb-config.c
+++ b/target/xtensa/core-dc233c/gdb-config.inc.c
diff --git a/target/xtensa/core-dc233c/xtensa-modules.c b/target/xtensa/core-dc233c/xtensa-modules.inc.c
index 7c20f82349..7c20f82349 100644
--- a/target/xtensa/core-dc233c/xtensa-modules.c
+++ b/target/xtensa/core-dc233c/xtensa-modules.inc.c
diff --git a/target/xtensa/core-de212.c b/target/xtensa/core-de212.c
index 466a467f7f..53775a97fa 100644
--- a/target/xtensa/core-de212.c
+++ b/target/xtensa/core-de212.c
@@ -36,13 +36,13 @@
#include "overlay_tool.h"
#define xtensa_modules xtensa_modules_de212
-#include "core-de212/xtensa-modules.c"
+#include "core-de212/xtensa-modules.inc.c"
static XtensaConfig de212 __attribute__((unused)) = {
.name = "de212",
.gdb_regmap = {
.reg = {
-#include "core-de212/gdb-config.c"
+#include "core-de212/gdb-config.inc.c"
}
},
.isa_internal = &xtensa_modules,
diff --git a/target/xtensa/core-de212/gdb-config.c b/target/xtensa/core-de212/gdb-config.inc.c
index 25510fc34c..25510fc34c 100644
--- a/target/xtensa/core-de212/gdb-config.c
+++ b/target/xtensa/core-de212/gdb-config.inc.c
diff --git a/target/xtensa/core-de212/xtensa-modules.c b/target/xtensa/core-de212/xtensa-modules.inc.c
index ef7674de3a..ef7674de3a 100644
--- a/target/xtensa/core-de212/xtensa-modules.c
+++ b/target/xtensa/core-de212/xtensa-modules.inc.c
diff --git a/target/xtensa/core-fsf.c b/target/xtensa/core-fsf.c
index f41de9a1aa..01932bdc8b 100644
--- a/target/xtensa/core-fsf.c
+++ b/target/xtensa/core-fsf.c
@@ -36,7 +36,7 @@
#include "overlay_tool.h"
#define xtensa_modules xtensa_modules_fsf
-#include "core-fsf/xtensa-modules.c"
+#include "core-fsf/xtensa-modules.inc.c"
static XtensaConfig fsf __attribute__((unused)) = {
.name = "fsf",
diff --git a/target/xtensa/core-fsf/xtensa-modules.c b/target/xtensa/core-fsf/xtensa-modules.inc.c
index f7de2dec15..f7de2dec15 100644
--- a/target/xtensa/core-fsf/xtensa-modules.c
+++ b/target/xtensa/core-fsf/xtensa-modules.inc.c
diff --git a/target/xtensa/core-sample_controller.c b/target/xtensa/core-sample_controller.c
index 879e853a92..c622335ca5 100644
--- a/target/xtensa/core-sample_controller.c
+++ b/target/xtensa/core-sample_controller.c
@@ -36,13 +36,13 @@
#include "overlay_tool.h"
#define xtensa_modules xtensa_modules_sample_controller
-#include "core-sample_controller/xtensa-modules.c"
+#include "core-sample_controller/xtensa-modules.inc.c"
static XtensaConfig sample_controller __attribute__((unused)) = {
.name = "sample_controller",
.gdb_regmap = {
.reg = {
-#include "core-sample_controller/gdb-config.c"
+#include "core-sample_controller/gdb-config.inc.c"
}
},
.isa_internal = &xtensa_modules,
diff --git a/target/xtensa/core-sample_controller/gdb-config.c b/target/xtensa/core-sample_controller/gdb-config.inc.c
index 99e172d819..99e172d819 100644
--- a/target/xtensa/core-sample_controller/gdb-config.c
+++ b/target/xtensa/core-sample_controller/gdb-config.inc.c
diff --git a/target/xtensa/core-sample_controller/xtensa-modules.c b/target/xtensa/core-sample_controller/xtensa-modules.inc.c
index fba41b99ae..fba41b99ae 100644
--- a/target/xtensa/core-sample_controller/xtensa-modules.c
+++ b/target/xtensa/core-sample_controller/xtensa-modules.inc.c
diff --git a/target/xtensa/import_core.sh b/target/xtensa/import_core.sh
index 32255eea9b..af6c610479 100755
--- a/target/xtensa/import_core.sh
+++ b/target/xtensa/import_core.sh
@@ -22,7 +22,7 @@ mkdir -p "$TARGET"
tar -xf "$OVERLAY" -C "$TARGET" --strip-components=1 \
--xform='s/core/core-isa/' config/core.h
tar -xf "$OVERLAY" -O gdb/xtensa-config.c | \
- sed -n '1,/*\//p;/XTREG/,/XTREG_END/p' > "$TARGET"/gdb-config.c
+ sed -n '1,/*\//p;/XTREG/,/XTREG_END/p' > "$TARGET"/gdb-config.inc.c
#
# Fix up known issues in the xtensa-modules.c
#
@@ -33,7 +33,8 @@ tar -xf "$OVERLAY" -O binutils/xtensa-modules.c | \
-e '/^uint32 \*bypass_entry(int i)/,/}/d' \
-e '/^#include "ansidecl.h"/d' \
-e '/^Slot_[a-zA-Z0-9_]\+_decode (const xtensa_insnbuf insn)/,/^}/s/^ return 0;$/ return XTENSA_UNDEFINED;/' \
- > "$TARGET"/xtensa-modules.c
+ -e 's/#include <xtensa-isa.h>/#include "xtensa-isa.h"/' \
+ > "$TARGET"/xtensa-modules.inc.c
cat <<EOF > "${TARGET}.c"
#include "qemu/osdep.h"
@@ -47,13 +48,13 @@ cat <<EOF > "${TARGET}.c"
#include "overlay_tool.h"
#define xtensa_modules xtensa_modules_$NAME
-#include "core-$NAME/xtensa-modules.c"
+#include "core-$NAME/xtensa-modules.inc.c"
static XtensaConfig $NAME __attribute__((unused)) = {
.name = "$NAME",
.gdb_regmap = {
.reg = {
-#include "core-$NAME/gdb-config.c"
+#include "core-$NAME/gdb-config.inc.c"
}
},
.isa_internal = &xtensa_modules,
diff --git a/tests/tcg/xtensa/Makefile b/tests/tcg/xtensa/Makefile
index 2882c431e4..091518c055 100644
--- a/tests/tcg/xtensa/Makefile
+++ b/tests/tcg/xtensa/Makefile
@@ -5,7 +5,7 @@ CROSS=xtensa-$(CORE)-elf-
ifndef XT
SIM = ../../../xtensa-softmmu/qemu-system-xtensa
-SIMFLAGS = -M sim -cpu $(CORE) -nographic -semihosting -icount 7 $(EXTFLAGS) -kernel
+SIMFLAGS = -M sim -cpu $(CORE) -nographic -semihosting -icount 6 $(EXTFLAGS) -kernel
SIMDEBUG = -s -S
else
SIM = xt-run
diff --git a/tests/test-aio.c b/tests/test-aio.c
index 54e20d6ab1..86fb73b3d5 100644
--- a/tests/test-aio.c
+++ b/tests/test-aio.c
@@ -16,6 +16,8 @@
#include "qemu/timer.h"
#include "qemu/sockets.h"
#include "qemu/error-report.h"
+#include "qemu/coroutine.h"
+#include "qemu/main-loop.h"
static AioContext *ctx;
@@ -827,24 +829,59 @@ static void test_source_timer_schedule(void)
timer_del(&data.timer);
}
+/*
+ * Check that aio_co_enter() can chain many times
+ *
+ * Two coroutines should be able to invoke each other via aio_co_enter() many
+ * times without hitting a limit like stack exhaustion. In other words, the
+ * calls should be chained instead of nested.
+ */
-/* End of tests. */
+typedef struct {
+ Coroutine *other;
+ unsigned i;
+ unsigned max;
+} ChainData;
-int main(int argc, char **argv)
+static void coroutine_fn chain(void *opaque)
{
- Error *local_error = NULL;
- GSource *src;
+ ChainData *data = opaque;
- init_clocks(NULL);
+ for (data->i = 0; data->i < data->max; data->i++) {
+ /* Queue up the other coroutine... */
+ aio_co_enter(ctx, data->other);
- ctx = aio_context_new(&local_error);
- if (!ctx) {
- error_reportf_err(local_error, "Failed to create AIO Context: ");
- exit(1);
+ /* ...and give control to it */
+ qemu_coroutine_yield();
}
- src = aio_get_g_source(ctx);
- g_source_attach(src, NULL);
- g_source_unref(src);
+}
+
+static void test_queue_chaining(void)
+{
+ /* This number of iterations hit stack exhaustion in the past: */
+ ChainData data_a = { .max = 25000 };
+ ChainData data_b = { .max = 25000 };
+
+ data_b.other = qemu_coroutine_create(chain, &data_a);
+ data_a.other = qemu_coroutine_create(chain, &data_b);
+
+ qemu_coroutine_enter(data_b.other);
+
+ g_assert_cmpint(data_a.i, ==, data_a.max);
+ g_assert_cmpint(data_b.i, ==, data_b.max - 1);
+
+ /* Allow the second coroutine to terminate */
+ qemu_coroutine_enter(data_a.other);
+
+ g_assert_cmpint(data_b.i, ==, data_b.max);
+}
+
+/* End of tests. */
+
+int main(int argc, char **argv)
+{
+ qemu_init_main_loop(&error_fatal);
+ ctx = qemu_get_aio_context();
while (g_main_context_iteration(NULL, false));
@@ -864,6 +901,8 @@ int main(int argc, char **argv)
g_test_add_func("/aio/external-client", test_aio_external_client);
g_test_add_func("/aio/timer/schedule", test_timer_schedule);
+ g_test_add_func("/aio/coroutine/queue-chaining", test_queue_chaining);
+
g_test_add_func("/aio-gsource/flush", test_source_flush);
g_test_add_func("/aio-gsource/bh/schedule", test_source_bh_schedule);
g_test_add_func("/aio-gsource/bh/schedule10", test_source_bh_schedule10);
diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c
index 5a80c10690..27438a1858 100644
--- a/util/qemu-coroutine-lock.c
+++ b/util/qemu-coroutine-lock.c
@@ -68,40 +68,6 @@ void coroutine_fn qemu_co_queue_wait_impl(CoQueue *queue, QemuLockable *lock)
}
}
-/**
- * qemu_co_queue_run_restart:
- *
- * Enter each coroutine that was previously marked for restart by
- * qemu_co_queue_next() or qemu_co_queue_restart_all(). This function is
- * invoked by the core coroutine code when the current coroutine yields or
- * terminates.
- */
-void qemu_co_queue_run_restart(Coroutine *co)
-{
- Coroutine *next;
- QSIMPLEQ_HEAD(, Coroutine) tmp_queue_wakeup =
- QSIMPLEQ_HEAD_INITIALIZER(tmp_queue_wakeup);
-
- trace_qemu_co_queue_run_restart(co);
-
- /* Because "co" has yielded, any coroutine that we wakeup can resume it.
- * If this happens and "co" terminates, co->co_queue_wakeup becomes
- * invalid memory. Therefore, use a temporary queue and do not touch
- * the "co" coroutine as soon as you enter another one.
- *
- * In its turn resumed "co" can populate "co_queue_wakeup" queue with
- * new coroutines to be woken up. The caller, who has resumed "co",
- * will be responsible for traversing the same queue, which may cause
- * a different wakeup order but not any missing wakeups.
- */
- QSIMPLEQ_CONCAT(&tmp_queue_wakeup, &co->co_queue_wakeup);
-
- while ((next = QSIMPLEQ_FIRST(&tmp_queue_wakeup))) {
- QSIMPLEQ_REMOVE_HEAD(&tmp_queue_wakeup, co_queue_next);
- qemu_coroutine_enter(next);
- }
-}
-
static bool qemu_co_queue_do_restart(CoQueue *queue, bool single)
{
Coroutine *next;
diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c
index 9eff7fd450..1ba4191b84 100644
--- a/util/qemu-coroutine.c
+++ b/util/qemu-coroutine.c
@@ -104,57 +104,65 @@ static void coroutine_delete(Coroutine *co)
void qemu_aio_coroutine_enter(AioContext *ctx, Coroutine *co)
{
- Coroutine *self = qemu_coroutine_self();
- CoroutineAction ret;
-
- /* Cannot rely on the read barrier for co in aio_co_wake(), as there are
- * callers outside of aio_co_wake() */
- const char *scheduled = atomic_mb_read(&co->scheduled);
+ QSIMPLEQ_HEAD(, Coroutine) pending = QSIMPLEQ_HEAD_INITIALIZER(pending);
+ Coroutine *from = qemu_coroutine_self();
- trace_qemu_aio_coroutine_enter(ctx, self, co, co->entry_arg);
+ QSIMPLEQ_INSERT_TAIL(&pending, co, co_queue_next);
- /* if the Coroutine has already been scheduled, entering it again will
- * cause us to enter it twice, potentially even after the coroutine has
- * been deleted */
- if (scheduled) {
- fprintf(stderr,
- "%s: Co-routine was already scheduled in '%s'\n",
- __func__, scheduled);
- abort();
- }
+ /* Run co and any queued coroutines */
+ while (!QSIMPLEQ_EMPTY(&pending)) {
+ Coroutine *to = QSIMPLEQ_FIRST(&pending);
+ CoroutineAction ret;
- if (co->caller) {
- fprintf(stderr, "Co-routine re-entered recursively\n");
- abort();
- }
+ /* Cannot rely on the read barrier for to in aio_co_wake(), as there are
+ * callers outside of aio_co_wake() */
+ const char *scheduled = atomic_mb_read(&to->scheduled);
- co->caller = self;
- co->ctx = ctx;
+ QSIMPLEQ_REMOVE_HEAD(&pending, co_queue_next);
- /* Store co->ctx before anything that stores co. Matches
- * barrier in aio_co_wake and qemu_co_mutex_wake.
- */
- smp_wmb();
+ trace_qemu_aio_coroutine_enter(ctx, from, to, to->entry_arg);
- ret = qemu_coroutine_switch(self, co, COROUTINE_ENTER);
-
- qemu_co_queue_run_restart(co);
+ /* if the Coroutine has already been scheduled, entering it again will
+ * cause us to enter it twice, potentially even after the coroutine has
+ * been deleted */
+ if (scheduled) {
+ fprintf(stderr,
+ "%s: Co-routine was already scheduled in '%s'\n",
+ __func__, scheduled);
+ abort();
+ }
- /* Beware, if ret == COROUTINE_YIELD and qemu_co_queue_run_restart()
- * has started any other coroutine, "co" might have been reentered
- * and even freed by now! So be careful and do not touch it.
- */
+ if (to->caller) {
+ fprintf(stderr, "Co-routine re-entered recursively\n");
+ abort();
+ }
- switch (ret) {
- case COROUTINE_YIELD:
- return;
- case COROUTINE_TERMINATE:
- assert(!co->locks_held);
- trace_qemu_coroutine_terminate(co);
- coroutine_delete(co);
- return;
- default:
- abort();
+ to->caller = from;
+ to->ctx = ctx;
+
+ /* Store to->ctx before anything that stores to. Matches
+ * barrier in aio_co_wake and qemu_co_mutex_wake.
+ */
+ smp_wmb();
+
+ ret = qemu_coroutine_switch(from, to, COROUTINE_ENTER);
+
+ /* Queued coroutines are run depth-first; previously pending coroutines
+ * run after those queued more recently.
+ */
+ QSIMPLEQ_PREPEND(&pending, &to->co_queue_wakeup);
+
+ switch (ret) {
+ case COROUTINE_YIELD:
+ break;
+ case COROUTINE_TERMINATE:
+ assert(!to->locks_held);
+ trace_qemu_coroutine_terminate(to);
+ coroutine_delete(to);
+ break;
+ default:
+ abort();
+ }
}
}