diff --git a/qemu-common.h b/qemu-common.h index aca2674622..0c6f4de3f2 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -70,6 +70,7 @@ typedef void QEMUBHFunc(void *opaque); QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque); void qemu_bh_schedule(QEMUBH *bh); +void qemu_bh_schedule_idle(QEMUBH *bh); void qemu_bh_cancel(QEMUBH *bh); void qemu_bh_delete(QEMUBH *bh); int qemu_bh_poll(void); diff --git a/vl.c b/vl.c index 1afe36e6e9..137074b9ef 100644 --- a/vl.c +++ b/vl.c @@ -7578,6 +7578,8 @@ struct QEMUBH { QEMUBHFunc *cb; void *opaque; int scheduled; + int idle; + int deleted; QEMUBH *next; }; @@ -7591,37 +7593,56 @@ QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque) return NULL; bh->cb = cb; bh->opaque = opaque; + bh->next = first_bh; + first_bh = bh; return bh; } int qemu_bh_poll(void) { - QEMUBH *bh, **pbh; + QEMUBH *bh, **bhp; int ret; ret = 0; - for(;;) { - pbh = &first_bh; - bh = *pbh; - if (!bh) - break; - ret = 1; - *pbh = bh->next; - bh->scheduled = 0; - bh->cb(bh->opaque); + for (bh = first_bh; bh; bh = bh->next) { + if (!bh->deleted && bh->scheduled) { + bh->scheduled = 0; + if (!bh->idle) + ret = 1; + bh->idle = 0; + bh->cb(bh->opaque); + } } + + /* remove deleted bhs */ + bhp = &first_bh; + while (*bhp) { + bh = *bhp; + if (bh->deleted) { + *bhp = bh->next; + qemu_free(bh); + } else + bhp = &bh->next; + } + return ret; } +void qemu_bh_schedule_idle(QEMUBH *bh) +{ + if (bh->scheduled) + return; + bh->scheduled = 1; + bh->idle = 1; +} + void qemu_bh_schedule(QEMUBH *bh) { CPUState *env = cpu_single_env; if (bh->scheduled) return; bh->scheduled = 1; - bh->next = first_bh; - first_bh = bh; - + bh->idle = 0; /* stop the currently executing CPU to execute the BH ASAP */ if (env) { cpu_interrupt(env, CPU_INTERRUPT_EXIT); @@ -7630,20 +7651,13 @@ void qemu_bh_schedule(QEMUBH *bh) void qemu_bh_cancel(QEMUBH *bh) { - QEMUBH **pbh; - if (bh->scheduled) { - pbh = &first_bh; - while (*pbh != bh) - pbh = &(*pbh)->next; - *pbh = bh->next; - bh->scheduled = 0; - } + bh->scheduled = 0; } void qemu_bh_delete(QEMUBH *bh) { - qemu_bh_cancel(bh); - qemu_free(bh); + bh->scheduled = 0; + bh->deleted = 1; } /***********************************************************/