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