xref: /qemu/util/async.c (revision 648fb0ea5e9d7f32c80ec23c3ece4321403dfecd)
14f999d05SKevin Wolf /*
24f999d05SKevin Wolf  * QEMU System Emulator
34f999d05SKevin Wolf  *
44f999d05SKevin Wolf  * Copyright (c) 2003-2008 Fabrice Bellard
54f999d05SKevin Wolf  *
64f999d05SKevin Wolf  * Permission is hereby granted, free of charge, to any person obtaining a copy
74f999d05SKevin Wolf  * of this software and associated documentation files (the "Software"), to deal
84f999d05SKevin Wolf  * in the Software without restriction, including without limitation the rights
94f999d05SKevin Wolf  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
104f999d05SKevin Wolf  * copies of the Software, and to permit persons to whom the Software is
114f999d05SKevin Wolf  * furnished to do so, subject to the following conditions:
124f999d05SKevin Wolf  *
134f999d05SKevin Wolf  * The above copyright notice and this permission notice shall be included in
144f999d05SKevin Wolf  * all copies or substantial portions of the Software.
154f999d05SKevin Wolf  *
164f999d05SKevin Wolf  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
174f999d05SKevin Wolf  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
184f999d05SKevin Wolf  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
194f999d05SKevin Wolf  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
204f999d05SKevin Wolf  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
214f999d05SKevin Wolf  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
224f999d05SKevin Wolf  * THE SOFTWARE.
234f999d05SKevin Wolf  */
244f999d05SKevin Wolf 
254f999d05SKevin Wolf #include "qemu-common.h"
269a1e9481SKevin Wolf #include "qemu-aio.h"
279a1e9481SKevin Wolf 
289a1e9481SKevin Wolf /* Anchor of the list of Bottom Halves belonging to the context */
29384acbf4SKevin Wolf static struct QEMUBH *first_bh;
304f999d05SKevin Wolf 
314f999d05SKevin Wolf /***********************************************************/
324f999d05SKevin Wolf /* bottom halves (can be seen as timers which expire ASAP) */
334f999d05SKevin Wolf 
344f999d05SKevin Wolf struct QEMUBH {
354f999d05SKevin Wolf     QEMUBHFunc *cb;
364f999d05SKevin Wolf     void *opaque;
374f999d05SKevin Wolf     int scheduled;
384f999d05SKevin Wolf     int idle;
394f999d05SKevin Wolf     int deleted;
404f999d05SKevin Wolf     QEMUBH *next;
414f999d05SKevin Wolf };
424f999d05SKevin Wolf 
434f999d05SKevin Wolf QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
444f999d05SKevin Wolf {
454f999d05SKevin Wolf     QEMUBH *bh;
467267c094SAnthony Liguori     bh = g_malloc0(sizeof(QEMUBH));
474f999d05SKevin Wolf     bh->cb = cb;
484f999d05SKevin Wolf     bh->opaque = opaque;
49384acbf4SKevin Wolf     bh->next = first_bh;
50384acbf4SKevin Wolf     first_bh = bh;
514f999d05SKevin Wolf     return bh;
524f999d05SKevin Wolf }
534f999d05SKevin Wolf 
544f999d05SKevin Wolf int qemu_bh_poll(void)
554f999d05SKevin Wolf {
567887f620SKevin Wolf     QEMUBH *bh, **bhp, *next;
574f999d05SKevin Wolf     int ret;
58*648fb0eaSKevin Wolf     static int nesting = 0;
59*648fb0eaSKevin Wolf 
60*648fb0eaSKevin Wolf     nesting++;
614f999d05SKevin Wolf 
624f999d05SKevin Wolf     ret = 0;
63384acbf4SKevin Wolf     for (bh = first_bh; bh; bh = next) {
647887f620SKevin Wolf         next = bh->next;
654f999d05SKevin Wolf         if (!bh->deleted && bh->scheduled) {
664f999d05SKevin Wolf             bh->scheduled = 0;
674f999d05SKevin Wolf             if (!bh->idle)
684f999d05SKevin Wolf                 ret = 1;
694f999d05SKevin Wolf             bh->idle = 0;
704f999d05SKevin Wolf             bh->cb(bh->opaque);
714f999d05SKevin Wolf         }
724f999d05SKevin Wolf     }
734f999d05SKevin Wolf 
74*648fb0eaSKevin Wolf     nesting--;
75*648fb0eaSKevin Wolf 
764f999d05SKevin Wolf     /* remove deleted bhs */
77*648fb0eaSKevin Wolf     if (!nesting) {
78384acbf4SKevin Wolf         bhp = &first_bh;
794f999d05SKevin Wolf         while (*bhp) {
804f999d05SKevin Wolf             bh = *bhp;
814f999d05SKevin Wolf             if (bh->deleted) {
824f999d05SKevin Wolf                 *bhp = bh->next;
837267c094SAnthony Liguori                 g_free(bh);
84*648fb0eaSKevin Wolf             } else {
854f999d05SKevin Wolf                 bhp = &bh->next;
864f999d05SKevin Wolf             }
87*648fb0eaSKevin Wolf         }
88*648fb0eaSKevin Wolf     }
894f999d05SKevin Wolf 
904f999d05SKevin Wolf     return ret;
914f999d05SKevin Wolf }
924f999d05SKevin Wolf 
934f999d05SKevin Wolf void qemu_bh_schedule_idle(QEMUBH *bh)
944f999d05SKevin Wolf {
954f999d05SKevin Wolf     if (bh->scheduled)
964f999d05SKevin Wolf         return;
974f999d05SKevin Wolf     bh->scheduled = 1;
984f999d05SKevin Wolf     bh->idle = 1;
994f999d05SKevin Wolf }
1004f999d05SKevin Wolf 
1014f999d05SKevin Wolf void qemu_bh_schedule(QEMUBH *bh)
1024f999d05SKevin Wolf {
1034f999d05SKevin Wolf     if (bh->scheduled)
1044f999d05SKevin Wolf         return;
1054f999d05SKevin Wolf     bh->scheduled = 1;
1064f999d05SKevin Wolf     bh->idle = 0;
1074f999d05SKevin Wolf     /* stop the currently executing CPU to execute the BH ASAP */
1084f999d05SKevin Wolf     qemu_notify_event();
1094f999d05SKevin Wolf }
1104f999d05SKevin Wolf 
1114f999d05SKevin Wolf void qemu_bh_cancel(QEMUBH *bh)
1124f999d05SKevin Wolf {
1134f999d05SKevin Wolf     bh->scheduled = 0;
1144f999d05SKevin Wolf }
1154f999d05SKevin Wolf 
1164f999d05SKevin Wolf void qemu_bh_delete(QEMUBH *bh)
1174f999d05SKevin Wolf {
1184f999d05SKevin Wolf     bh->scheduled = 0;
1194f999d05SKevin Wolf     bh->deleted = 1;
1204f999d05SKevin Wolf }
1214f999d05SKevin Wolf 
1224f999d05SKevin Wolf void qemu_bh_update_timeout(int *timeout)
1234f999d05SKevin Wolf {
1244f999d05SKevin Wolf     QEMUBH *bh;
1254f999d05SKevin Wolf 
126384acbf4SKevin Wolf     for (bh = first_bh; bh; bh = bh->next) {
1274f999d05SKevin Wolf         if (!bh->deleted && bh->scheduled) {
1284f999d05SKevin Wolf             if (bh->idle) {
1294f999d05SKevin Wolf                 /* idle bottom halves will be polled at least
1304f999d05SKevin Wolf                  * every 10ms */
1314f999d05SKevin Wolf                 *timeout = MIN(10, *timeout);
1324f999d05SKevin Wolf             } else {
1334f999d05SKevin Wolf                 /* non-idle bottom halves will be executed
1344f999d05SKevin Wolf                  * immediately */
1354f999d05SKevin Wolf                 *timeout = 0;
1364f999d05SKevin Wolf                 break;
1374f999d05SKevin Wolf             }
1384f999d05SKevin Wolf         }
1394f999d05SKevin Wolf     }
1404f999d05SKevin Wolf }
1414f999d05SKevin Wolf 
142