• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
qlooptimer_startRelative(void * impl,Duration timeout_ms)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
qlooptimer_startAbsolute(void * impl,Duration deadline_ms)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);
50 }
51 
52 static void
qlooptimer_stop(void * impl)53 qlooptimer_stop(void* impl)
54 {
55     QEMUTimer* tt = impl;
56     qemu_del_timer(tt);
57 }
58 
59 static int
qlooptimer_isActive(void * impl)60 qlooptimer_isActive(void* impl)
61 {
62     QEMUTimer* tt = impl;
63     return qemu_timer_pending(tt);
64 }
65 
66 static void
qlooptimer_free(void * impl)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
qlooper_timer_init(Looper * looper,LoopTimer * timer,LoopTimerFunc callback,void * opaque)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*
qloopio_new(int fd,LoopIoFunc callback,void * opaque,QLooper * qlooper)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
qloopio_removePending(QLoopIo * io)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
qloopio_setReady(QLoopIo * io,unsigned flag)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
qloopio_handleRead(void * opaque)180 qloopio_handleRead(void* opaque)
181 {
182     QLoopIo* io = opaque;
183     qloopio_setReady(io, LOOP_IO_READ);
184 }
185 
186 static void
qloopio_handleWrite(void * opaque)187 qloopio_handleWrite(void* opaque)
188 {
189     QLoopIo* io = opaque;
190     qloopio_setReady(io, LOOP_IO_WRITE);
191 }
192 
193 static void
qloopio_modify(QLoopIo * io,unsigned wanted)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
qloopio_wantRead(void * impl)214 qloopio_wantRead(void* impl)
215 {
216     QLoopIo* io = impl;
217     qloopio_modify(io, io->wanted | LOOP_IO_READ);
218 }
219 
220 static void
qloopio_wantWrite(void * impl)221 qloopio_wantWrite(void* impl)
222 {
223     QLoopIo* io = impl;
224     qloopio_modify(io, io->wanted | LOOP_IO_WRITE);
225 }
226 
227 static void
qloopio_dontWantRead(void * impl)228 qloopio_dontWantRead(void* impl)
229 {
230     QLoopIo* io = impl;
231     qloopio_modify(io, io->wanted & ~LOOP_IO_READ);
232 }
233 
234 static void
qloopio_dontWantWrite(void * impl)235 qloopio_dontWantWrite(void* impl)
236 {
237     QLoopIo* io = impl;
238     qloopio_modify(io, io->wanted & ~LOOP_IO_WRITE);
239 }
240 
241 static void
qloopio_free(void * impl)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
qloopio_poll(void * impl)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
qlooper_io_init(Looper * looper,LoopIo * loopio,int fd,LoopIoFunc callback,void * opaque)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
qlooper_addIo(QLooper * looper,QLoopIo * io)296 qlooper_addIo(QLooper* looper, QLoopIo* io)
297 {
298     io->next        = looper->io_list;
299     looper->io_list = io;
300 }
301 
302 static void
qlooper_delIo(QLooper * looper,QLoopIo * io)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
qlooper_addPendingIo(QLooper * looper,QLoopIo * io)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
qlooper_delPendingIo(QLooper * looper,QLoopIo * io)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
qlooper_handle_io_bh(void * opaque)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
qlooper_now(Looper * ll)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
qlooper_forceQuit(Looper * ll)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
qlooper_run(Looper * ll,Duration deadline_ms)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
qlooper_destroy(Looper * ll)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*
looper_newCore(void)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