summary refs log tree commit diff stats
path: root/vl.c
diff options
context:
space:
mode:
Diffstat (limited to 'vl.c')
-rw-r--r--vl.c60
1 files changed, 37 insertions, 23 deletions
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;
 }
 
 /***********************************************************/