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 "sysemu/char.h"
20#include "android/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
32static void
33qlooptimer_startRelative(void* impl, Duration timeout_ms)
34{
35    QEMUTimer* tt = impl;
36    if (timeout_ms == DURATION_INFINITE)
37        timer_del(tt);
38    else
39        timer_mod(tt, qemu_clock_get_ms(QEMU_CLOCK_HOST) + timeout_ms);
40}
41
42static void
43qlooptimer_startAbsolute(void* impl, Duration deadline_ms)
44{
45    QEMUTimer* tt = impl;
46    if (deadline_ms == DURATION_INFINITE)
47        timer_del(tt);
48    else
49        timer_mod(tt, deadline_ms);
50}
51
52static void
53qlooptimer_stop(void* impl)
54{
55    QEMUTimer* tt = impl;
56    timer_del(tt);
57}
58
59static int
60qlooptimer_isActive(void* impl)
61{
62    QEMUTimer* tt = impl;
63    return timer_pending(tt);
64}
65
66static void
67qlooptimer_free(void* impl)
68{
69    QEMUTimer* tt = impl;
70    timer_free(tt);
71}
72
73static const LoopTimerClass  qlooptimer_class = {
74    qlooptimer_startRelative,
75    qlooptimer_startAbsolute,
76    qlooptimer_stop,
77    qlooptimer_isActive,
78    qlooptimer_free
79};
80
81static void
82qlooper_timer_init(Looper*        looper,
83                   LoopTimer*     timer,
84                   LoopTimerFunc  callback,
85                   void*          opaque)
86{
87    timer->clazz = (LoopTimerClass*) &qlooptimer_class;
88    timer->impl  = timer_new(QEMU_CLOCK_HOST, SCALE_MS, 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
122typedef struct QLoopIo QLoopIo;
123
124typedef struct QLooper  QLooper;
125
126struct 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
137static void qlooper_addIo(QLooper*  looper, QLoopIo* io);
138static void qlooper_delIo(QLooper*  looper, QLoopIo* io);
139
140static QLoopIo*
141qloopio_new(int fd, LoopIoFunc callback, void* opaque, QLooper* qlooper)
142{
143    QLoopIo*  io = g_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
158static void qlooper_addPendingIo(QLooper* qlooper, QLoopIo* io);
159static void qlooper_delPendingIo(QLooper* qlooper, QLoopIo*  io);
160
161static void
162qloopio_removePending(QLoopIo* io)
163{
164    if (io->ready != 0) {
165        qlooper_delPendingIo(io->looper, io);
166        io->ready = 0;
167    }
168}
169
170static void
171qloopio_setReady(QLoopIo* io, unsigned flag)
172{
173    if (io->ready == 0) {
174        qlooper_addPendingIo(io->looper, io);
175    }
176    io->ready |= flag;
177}
178
179static void
180qloopio_handleRead(void* opaque)
181{
182    QLoopIo* io = opaque;
183    qloopio_setReady(io, LOOP_IO_READ);
184}
185
186static void
187qloopio_handleWrite(void* opaque)
188{
189    QLoopIo* io = opaque;
190    qloopio_setReady(io, LOOP_IO_WRITE);
191}
192
193static void
194qloopio_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
213static void
214qloopio_wantRead(void* impl)
215{
216    QLoopIo* io = impl;
217    qloopio_modify(io, io->wanted | LOOP_IO_READ);
218}
219
220static void
221qloopio_wantWrite(void* impl)
222{
223    QLoopIo* io = impl;
224    qloopio_modify(io, io->wanted | LOOP_IO_WRITE);
225}
226
227static void
228qloopio_dontWantRead(void* impl)
229{
230    QLoopIo* io = impl;
231    qloopio_modify(io, io->wanted & ~LOOP_IO_READ);
232}
233
234static void
235qloopio_dontWantWrite(void* impl)
236{
237    QLoopIo* io = impl;
238    qloopio_modify(io, io->wanted & ~LOOP_IO_WRITE);
239}
240
241static void
242qloopio_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    g_free(io);
255}
256
257static unsigned
258qloopio_poll(void* impl)
259{
260    QLoopIo* io = impl;
261    return io->ready;
262}
263
264static 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
273static void
274qlooper_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
288struct QLooper {
289    Looper    looper;
290    QLoopIo*  io_list;
291    QLoopIo*  io_pending;
292    QEMUBH*   io_bh;
293};
294
295static void
296qlooper_addIo(QLooper* looper, QLoopIo* io)
297{
298    io->next        = looper->io_list;
299    looper->io_list = io;
300}
301
302static void
303qlooper_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
318static void
319qlooper_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
328static void
329qlooper_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 */
349static void
350qlooper_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
370static Duration
371qlooper_now(Looper* ll)
372{
373    return qemu_clock_get_ms(QEMU_CLOCK_HOST);
374}
375
376extern void qemu_system_shutdown_request(void);
377
378static void
379qlooper_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. */
386int
387qlooper_run(Looper* ll, Duration deadline_ms)
388{
389    APANIC("Trying to run the QEMU main event loop explicitely!");
390    return EINVAL;
391}
392
393static void
394qlooper_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    g_free(looper);
404}
405
406Looper*
407looper_newCore(void)
408{
409    QLooper*  looper = g_malloc0(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