Home | History | Annotate | Download | only in android
      1 /* Copyright (C) 2010 The Android Open Source Project
      2 **
      3 ** This software is licensed under the terms of the GNU General Public
      4 ** License version 2, as published by the Free Software Foundation, and
      5 ** may be copied, distributed, and modified under those terms.
      6 **
      7 ** This program is distributed in the hope that it will be useful,
      8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10 ** GNU General Public License for more details.
     11 */
     12 
     13 /* Implement the Looper interface on top of the QEMU main event loop */
     14 
     15 #include <android/looper.h>
     16 #include <android/utils/panic.h>
     17 #include "qemu-common.h"
     18 #include "qemu-timer.h"
     19 #include "qemu-char.h"
     20 #include "sockets.h"  /* for socket_set_nonblock() */
     21 
     22 /**********************************************************************
     23  **********************************************************************
     24  *****
     25  *****  T I M E R S
     26  *****
     27  **********************************************************************
     28  **********************************************************************/
     29 
     30 /* Model a timer simple as a QEMUTimer for the host_clock */
     31 
     32 static void
     33 qlooptimer_startRelative(void* impl, Duration timeout_ms)
     34 {
     35     QEMUTimer* tt = impl;
     36     if (timeout_ms == DURATION_INFINITE)
     37         qemu_del_timer(tt);
     38     else
     39         qemu_mod_timer(tt, qemu_get_clock_ms(host_clock) + timeout_ms);
     40 }
     41 
     42 static void
     43 qlooptimer_startAbsolute(void* impl, Duration deadline_ms)
     44 {
     45     QEMUTimer* tt = impl;
     46     if (deadline_ms == DURATION_INFINITE)
     47         qemu_del_timer(tt);
     48     else
     49         qemu_mod_timer(tt, deadline_ms*1000000);
     50 }
     51 
     52 static void
     53 qlooptimer_stop(void* impl)
     54 {
     55     QEMUTimer* tt = impl;
     56     qemu_del_timer(tt);
     57 }
     58 
     59 static int
     60 qlooptimer_isActive(void* impl)
     61 {
     62     QEMUTimer* tt = impl;
     63     return qemu_timer_pending(tt);
     64 }
     65 
     66 static void
     67 qlooptimer_free(void* impl)
     68 {
     69     QEMUTimer* tt = impl;
     70     qemu_free_timer(tt);
     71 }
     72 
     73 static const LoopTimerClass  qlooptimer_class = {
     74     qlooptimer_startRelative,
     75     qlooptimer_startAbsolute,
     76     qlooptimer_stop,
     77     qlooptimer_isActive,
     78     qlooptimer_free
     79 };
     80 
     81 static void
     82 qlooper_timer_init(Looper*        looper,
     83                    LoopTimer*     timer,
     84                    LoopTimerFunc  callback,
     85                    void*          opaque)
     86 {
     87     timer->clazz = (LoopTimerClass*) &qlooptimer_class;
     88     timer->impl  = qemu_new_timer_ms(host_clock, callback, opaque);
     89 }
     90 
     91 /**********************************************************************
     92  **********************************************************************
     93  *****
     94  *****  F I L E   D E S C R I P T O R S
     95  *****
     96  **********************************************************************
     97  **********************************************************************/
     98 
     99 /* Modeling the LoopIo is a bit more complex because the main event loop
    100  * will call different functions for read and write readiness, while our
    101  * users expect a single call with a mask of ready events.
    102  *
    103  * Since the QEMU main event loop looks like the following:
    104  *
    105  *    1/ perform select()
    106  *    2/ for each file descriptor:
    107  *         if readReady:
    108  *             call readHandler()
    109  *         if writeReady:
    110  *             call writeHandler()
    111  *    3/ run timers
    112  *    4/ run bottom-half handlers
    113  *
    114  * We're going to provide simple read and write handlers that only mark
    115  * the file descriptor for readiness, and put it on a "pending list".
    116  *
    117  * Then, we're going to schedule a bottom-half handler when such a pending
    118  * i/o event occurs, in order to call the user callback with the correct
    119  * flags.
    120  */
    121 
    122 typedef struct QLoopIo QLoopIo;
    123 
    124 typedef struct QLooper  QLooper;
    125 
    126 struct QLoopIo {
    127     int         fd;
    128     LoopIoFunc  user_callback;
    129     void*       user_opaque;
    130     unsigned    wanted;
    131     unsigned    ready;
    132     QLooper*    looper;
    133     QLoopIo*    pendingNext;
    134     QLoopIo*    next;
    135 };
    136 
    137 static void qlooper_addIo(QLooper*  looper, QLoopIo* io);
    138 static void qlooper_delIo(QLooper*  looper, QLoopIo* io);
    139 
    140 static QLoopIo*
    141 qloopio_new(int fd, LoopIoFunc callback, void* opaque, QLooper* qlooper)
    142 {
    143     QLoopIo*  io = qemu_malloc(sizeof(*io));
    144 
    145     io->fd = fd;
    146     io->user_callback = callback;
    147     io->user_opaque   = opaque;
    148     io->wanted        = 0;
    149     io->ready         = 0;
    150     io->looper        = qlooper;
    151     io->pendingNext   = NULL;
    152 
    153     qlooper_addIo(qlooper, io);
    154 
    155     return io;
    156 }
    157 
    158 static void qlooper_addPendingIo(QLooper* qlooper, QLoopIo* io);
    159 static void qlooper_delPendingIo(QLooper* qlooper, QLoopIo*  io);
    160 
    161 static void
    162 qloopio_removePending(QLoopIo* io)
    163 {
    164     if (io->ready != 0) {
    165         qlooper_delPendingIo(io->looper, io);
    166         io->ready = 0;
    167     }
    168 }
    169 
    170 static void
    171 qloopio_setReady(QLoopIo* io, unsigned flag)
    172 {
    173     if (io->ready == 0) {
    174         qlooper_addPendingIo(io->looper, io);
    175     }
    176     io->ready |= flag;
    177 }
    178 
    179 static void
    180 qloopio_handleRead(void* opaque)
    181 {
    182     QLoopIo* io = opaque;
    183     qloopio_setReady(io, LOOP_IO_READ);
    184 }
    185 
    186 static void
    187 qloopio_handleWrite(void* opaque)
    188 {
    189     QLoopIo* io = opaque;
    190     qloopio_setReady(io, LOOP_IO_WRITE);
    191 }
    192 
    193 static void
    194 qloopio_modify(QLoopIo* io, unsigned wanted)
    195 {
    196     /* no change, don't bother */
    197     if (wanted == io->wanted)
    198         return;
    199 
    200     /* if we're pending, but the new mask doesn't care about
    201      * out state, remove from pending list */
    202     if (io->ready && (io->ready & wanted) == 0) {
    203         qloopio_removePending(io);
    204     }
    205 
    206     /* recompute read/write handlers for QEMU */
    207     IOHandler* fd_read  = (wanted & LOOP_IO_READ)  ? qloopio_handleRead  : NULL;
    208     IOHandler* fd_write = (wanted & LOOP_IO_WRITE) ? qloopio_handleWrite : NULL;
    209     qemu_set_fd_handler(io->fd, fd_read, fd_write, io);
    210     io->wanted = wanted;
    211 }
    212 
    213 static void
    214 qloopio_wantRead(void* impl)
    215 {
    216     QLoopIo* io = impl;
    217     qloopio_modify(io, io->wanted | LOOP_IO_READ);
    218 }
    219 
    220 static void
    221 qloopio_wantWrite(void* impl)
    222 {
    223     QLoopIo* io = impl;
    224     qloopio_modify(io, io->wanted | LOOP_IO_WRITE);
    225 }
    226 
    227 static void
    228 qloopio_dontWantRead(void* impl)
    229 {
    230     QLoopIo* io = impl;
    231     qloopio_modify(io, io->wanted & ~LOOP_IO_READ);
    232 }
    233 
    234 static void
    235 qloopio_dontWantWrite(void* impl)
    236 {
    237     QLoopIo* io = impl;
    238     qloopio_modify(io, io->wanted & ~LOOP_IO_WRITE);
    239 }
    240 
    241 static void
    242 qloopio_free(void* impl)
    243 {
    244     QLoopIo* io = impl;
    245     if (io->ready)
    246         qloopio_removePending(io);
    247 
    248     /* remove from global list */
    249     qlooper_delIo(io->looper, io);
    250 
    251     /* make QEMU forget about this fd */
    252     qemu_set_fd_handler(io->fd, NULL, NULL, NULL);
    253     io->fd = -1;
    254     qemu_free(io);
    255 }
    256 
    257 static unsigned
    258 qloopio_poll(void* impl)
    259 {
    260     QLoopIo* io = impl;
    261     return io->ready;
    262 }
    263 
    264 static const LoopIoClass  qlooper_io_class = {
    265     qloopio_wantRead,
    266     qloopio_wantWrite,
    267     qloopio_dontWantRead,
    268     qloopio_dontWantWrite,
    269     qloopio_poll,
    270     qloopio_free
    271 };
    272 
    273 static void
    274 qlooper_io_init(Looper*     looper,
    275                 LoopIo*     loopio,
    276                 int         fd,
    277                 LoopIoFunc  callback,
    278                 void*       opaque)
    279 {
    280     QLoopIo* io = qloopio_new(fd, callback, opaque, (QLooper*)looper);
    281 
    282     socket_set_nonblock(fd);
    283 
    284     loopio->clazz = (LoopIoClass*) &qlooper_io_class;
    285     loopio->impl  = io;
    286 }
    287 
    288 struct QLooper {
    289     Looper    looper;
    290     QLoopIo*  io_list;
    291     QLoopIo*  io_pending;
    292     QEMUBH*   io_bh;
    293 };
    294 
    295 static void
    296 qlooper_addIo(QLooper* looper, QLoopIo* io)
    297 {
    298     io->next        = looper->io_list;
    299     looper->io_list = io;
    300 }
    301 
    302 static void
    303 qlooper_delIo(QLooper* looper, QLoopIo* io)
    304 {
    305     QLoopIo** pnode = &looper->io_list;
    306     for (;;) {
    307         if (*pnode == NULL)
    308             break;
    309         if (*pnode == io) {
    310             *pnode = io->next;
    311             io->next = NULL;
    312             break;
    313         }
    314         pnode = &(*pnode)->next;
    315     }
    316 }
    317 
    318 static void
    319 qlooper_addPendingIo(QLooper* looper, QLoopIo* io)
    320 {
    321     if (looper->io_pending == NULL) {
    322         qemu_bh_schedule(looper->io_bh);
    323     }
    324     io->pendingNext    = looper->io_pending;
    325     looper->io_pending = io;
    326 }
    327 
    328 static void
    329 qlooper_delPendingIo(QLooper* looper, QLoopIo* io)
    330 {
    331     QLoopIo** pnode = &looper->io_pending;
    332     for (;;) {
    333         if (*pnode == NULL)
    334             break;
    335         if (*pnode == io) {
    336             *pnode = io->pendingNext;
    337             break;
    338         }
    339         pnode = &(*pnode)->pendingNext;
    340     }
    341     io->pendingNext = NULL;
    342 }
    343 
    344 /* This function is called by the main event loop when pending i/o
    345  * events were registered with qlooper_addPendingIo(). It will parse
    346  * the list of pending QLoopIo and call the user callback with the
    347  * appropriate flags.
    348  */
    349 static void
    350 qlooper_handle_io_bh(void* opaque)
    351 {
    352     QLooper*  looper = opaque;
    353     QLoopIo*  io;
    354 
    355     while ((io = looper->io_pending) != NULL) {
    356         unsigned ready;
    357         /* extract from list */
    358         looper->io_pending = io->pendingNext;
    359         io->pendingNext    = NULL;
    360         /* call the user callback, clear io->ready before to
    361          * indicate that the item is not on the pending list
    362          * anymore.
    363          */
    364         ready     = io->ready;
    365         io->ready = 0;
    366         io->user_callback(io->user_opaque, io->fd, ready);
    367     }
    368 }
    369 
    370 static Duration
    371 qlooper_now(Looper* ll)
    372 {
    373     return qemu_get_clock_ms(host_clock);
    374 }
    375 
    376 extern void qemu_system_shutdown_request(void);
    377 
    378 static void
    379 qlooper_forceQuit(Looper* ll)
    380 {
    381     qemu_system_shutdown_request();
    382 }
    383 
    384 /* The user cannot call looper_run on the core event loop, because it
    385  * is started by qemu_main() explicitely instead, so just panic. */
    386 int
    387 qlooper_run(Looper* ll, Duration deadline_ms)
    388 {
    389     APANIC("Trying to run the QEMU main event loop explicitely!");
    390     return EINVAL;
    391 }
    392 
    393 static void
    394 qlooper_destroy(Looper* ll)
    395 {
    396     QLooper*  looper = (QLooper*)ll;
    397     QLoopIo*  io;
    398 
    399     while ((io = looper->io_list) != NULL)
    400         qloopio_free(io);
    401 
    402     qemu_bh_delete(looper->io_bh);
    403     qemu_free(looper);
    404 }
    405 
    406 Looper*
    407 looper_newCore(void)
    408 {
    409     QLooper*  looper = qemu_mallocz(sizeof(*looper));
    410 
    411     looper->io_list    = NULL;
    412     looper->io_pending = NULL;
    413     looper->io_bh      = qemu_bh_new(qlooper_handle_io_bh, looper);
    414 
    415     looper->looper.now        = qlooper_now;
    416     looper->looper.timer_init = qlooper_timer_init;
    417     looper->looper.io_init    = qlooper_io_init;
    418     looper->looper.run        = qlooper_run;
    419     looper->looper.forceQuit  = qlooper_forceQuit;
    420     looper->looper.destroy    = qlooper_destroy;
    421 
    422     return &looper->looper;
    423 }
    424