17a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner/* Copyright (C) 2010 The Android Open Source Project
27a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner**
37a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner** This software is licensed under the terms of the GNU General Public
47a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner** License version 2, as published by the Free Software Foundation, and
57a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner** may be copied, distributed, and modified under those terms.
67a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner**
77a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner** This program is distributed in the hope that it will be useful,
87a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner** but WITHOUT ANY WARRANTY; without even the implied warranty of
97a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
107a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner** GNU General Public License for more details.
117a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner*/
127a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
137a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner#include "android/utils/assert.h"
147a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner#include "android/utils/reflist.h"
157a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner#include "android/utils/refset.h"
167a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner#include "android/utils/system.h"
177a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner#include "android/looper.h"
18d413fa5f2916a2a46494edb320340486b262644cDavid 'Digit' Turner#include "android/iolooper.h"
19cc330d4169441727fecf1da08aee806fc021c4e2David 'Digit' Turner#include "android/sockets.h"
207a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner#include <inttypes.h>
217a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner#include <limits.h>
221bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner#include <errno.h>
237a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
247a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner/**********************************************************************
257a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner **********************************************************************
267a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner *****
277a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner *****  T I M E R S
287a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner *****
297a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner **********************************************************************
307a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner **********************************************************************/
317a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
327a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnertypedef struct GLoopTimer GLoopTimer;
337a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnertypedef struct GLoopIo    GLoopIo;
347a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnertypedef struct GLooper    GLooper;
357a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
367a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstruct GLoopTimer {
377a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    Duration      deadline;
387a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    LoopTimerFunc callback;
397a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    void*         opaque;
407a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLooper*      looper;
417a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLoopTimer*   activeNext;
427a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner};
437a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
447a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic Duration glooper_now(Looper* ll);
457a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
467a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void glooper_addActiveTimer(GLooper* looper, GLoopTimer* timer);
477a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void glooper_delActiveTimer(GLooper* looper, GLoopTimer* timer);
487a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void glooper_addTimer(GLooper* looper, GLoopTimer* timer);
497a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void glooper_delTimer(GLooper* looper, GLoopTimer* timer);
507a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
517a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
527a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerglooptimer_stop(void* impl)
537a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
547a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLoopTimer*  tt = impl;
557a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    if (tt->deadline != DURATION_INFINITE) {
567a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        glooper_delActiveTimer(tt->looper, tt);
577a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        tt->deadline = DURATION_INFINITE;
587a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    }
597a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
607a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
617a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
627a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerglooptimer_startAbsolute(void* impl, Duration deadline_ms)
637a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
647a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLoopTimer*  tt = impl;
657a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
667a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    /* Stop the timer if it was active */
677a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    if (tt->deadline != DURATION_INFINITE)
687a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        glooptimer_stop(tt);
697a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
707a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    /* Another way to stop a timer */
717a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    if (deadline_ms == DURATION_INFINITE)
727a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        return;
737a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
747a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    tt->deadline = deadline_ms;
757a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    glooper_addActiveTimer(tt->looper, tt);
767a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
777a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
787a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
797a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerglooptimer_startRelative(void* impl, Duration  timeout_ms)
807a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
817a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLoopTimer*  tt = impl;
827a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
837a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    if (timeout_ms == DURATION_INFINITE) {  /* another way to stop the timer */
847a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        glooptimer_stop(tt);
857a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    } else {
867a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        glooptimer_startAbsolute(tt, timeout_ms + glooper_now((Looper*)tt->looper));
877a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    }
887a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
897a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
907a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic int
917a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerglooptimer_isActive(void* impl)
927a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
937a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLoopTimer*  tt = impl;
947a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    return (tt->deadline != DURATION_INFINITE);
957a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
967a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
977a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
987a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerglooptimer_free(void* impl)
997a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
1007a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLoopTimer*  tt = impl;
1017a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
1027a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    if (tt->deadline != DURATION_INFINITE)
1037a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        glooptimer_stop(tt);
1047a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
1057a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    glooper_delTimer(tt->looper, tt);
1067a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    AFREE(tt);
1077a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
1087a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
1097a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic const LoopTimerClass  glooptimer_class = {
1107a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    glooptimer_startRelative,
1117a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    glooptimer_startAbsolute,
1127a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    glooptimer_stop,
1137a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    glooptimer_isActive,
1147a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    glooptimer_free
1157a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner};
1167a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
1177a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
1187a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerglooper_timer_init(Looper*       looper,
1197a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                   LoopTimer*    timer,
1207a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                   LoopTimerFunc callback,
1217a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                   void*         opaque)
1227a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
1237a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLoopTimer* tt;
1247a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
1257a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    ANEW0(tt);
1267a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
1277a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    tt->deadline = DURATION_INFINITE;
1287a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    tt->callback = callback;
1297a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    tt->opaque   = opaque;
1307a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    tt->looper   = (GLooper*) looper;
1317a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
1327a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    glooper_addTimer(tt->looper, tt);
1337a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
1347a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    timer->impl  = tt;
1357a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    timer->clazz = (LoopTimerClass*) &glooptimer_class;
1367a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
1377a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
1387a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner/**********************************************************************
1397a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner **********************************************************************
1407a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner *****
1417a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner *****  I / O
1427a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner *****
1437a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner **********************************************************************
1447a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner **********************************************************************/
1457a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
1467a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstruct GLoopIo {
1477a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    int         fd;
1487a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    LoopIoFunc  callback;
1497a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    void*       opaque;
1507a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    unsigned    wanted;
1517a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    unsigned    ready;
1527a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLooper*    looper;
1537a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner};
1547a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
1557a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void glooper_delPendingIo(GLooper* looper, GLoopIo* io);
1567a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void glooper_addIo(GLooper* looper, GLoopIo* io);
1577a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void glooper_delIo(GLooper* looper, GLoopIo* io);
1587a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void glooper_modifyFd(GLooper* looper, int fd, int oldwanted, int newwanted);
1597a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
1607a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner/* used to indicate that the set of wanted flags has changed */
1617a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
1627a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnergloopio_modify(GLoopIo* io, unsigned wanted)
1637a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
1647a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    /* If nothing changed, return */
1657a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    if (io->wanted == wanted)
1667a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        return;
1677a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
1687a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    /* If we are pending, and we're not interested by the
1697a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner     * current ready flags, remove from list */
1707a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    if (io->ready != 0 && (io->ready & wanted) == 0) {
1717a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        glooper_delPendingIo(io->looper, io);
1727a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    }
1737a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    io->ready &= wanted;
1747a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    glooper_modifyFd(io->looper, io->fd, io->wanted, wanted);
1757a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    io->wanted = wanted;
1767a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
1777a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
1787a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
1797a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnergloopio_wantRead(void* impl)
1807a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
1817a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLoopIo* io = impl;
1827a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    gloopio_modify(io, io->wanted | LOOP_IO_READ);
1837a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
1847a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
1857a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
1867a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnergloopio_wantWrite(void* impl)
1877a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
1887a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLoopIo* io = impl;
1897a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    gloopio_modify(io, io->wanted | LOOP_IO_WRITE);
1907a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
1917a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
1927a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
1937a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnergloopio_dontWantRead(void* impl)
1947a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
1957a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLoopIo* io = impl;
1967a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    gloopio_modify(io, io->wanted & ~LOOP_IO_READ);
1977a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
1987a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
1997a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
2007a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnergloopio_dontWantWrite(void* impl)
2017a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
2027a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLoopIo* io = impl;
2037a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    gloopio_modify(io, io->wanted & ~LOOP_IO_WRITE);
2047a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
2057a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
206a65e41529e4e3900372d54859f8c559cf79d953cDavid 'Digit' Turnerstatic unsigned
207a65e41529e4e3900372d54859f8c559cf79d953cDavid 'Digit' Turnergloopio_poll(void* impl)
208a65e41529e4e3900372d54859f8c559cf79d953cDavid 'Digit' Turner{
209a65e41529e4e3900372d54859f8c559cf79d953cDavid 'Digit' Turner    GLoopIo* io = impl;
210a65e41529e4e3900372d54859f8c559cf79d953cDavid 'Digit' Turner    return io->ready;
211a65e41529e4e3900372d54859f8c559cf79d953cDavid 'Digit' Turner}
212a65e41529e4e3900372d54859f8c559cf79d953cDavid 'Digit' Turner
2137a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
2147a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnergloopio_free(void* impl)
2157a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
2167a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLoopIo* io = impl;
2177a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    if (io->ready != 0)
2187a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        glooper_delPendingIo(io->looper, io);
2197a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
2207a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    glooper_delIo(io->looper, io);
2217a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    AFREE(io);
2227a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
2237a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
2247a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic LoopIoClass  gloopio_class = {
2257a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    gloopio_wantRead,
2267a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    gloopio_wantWrite,
2277a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    gloopio_dontWantRead,
2287a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    gloopio_dontWantWrite,
229a65e41529e4e3900372d54859f8c559cf79d953cDavid 'Digit' Turner    gloopio_poll,
2307a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    gloopio_free
2317a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner};
2327a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
2337a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
2347a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerglooper_io_init(Looper* looper, LoopIo* user, int fd, LoopIoFunc callback, void* opaque)
2357a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
2367a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLooper*  gg = (GLooper*)looper;
2377a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLoopIo*  io;
2387a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
2397a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    ANEW0(io);
2407a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    io->fd       = fd;
2417a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    io->callback = callback;
2427a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    io->opaque   = opaque;
2431bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner    io->looper   = (GLooper*) looper;
2447a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    io->wanted   = 0;
2457a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    io->ready    = 0;
2467a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
2471bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner    socket_set_nonblock(fd);
2481bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner
2497a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    glooper_addIo(gg, io);
2507a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
2517a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    user->impl  = io;
2527a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    user->clazz = (LoopIoClass*) &gloopio_class;
2537a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
2547a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
2557a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner/**********************************************************************
2567a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner **********************************************************************
2577a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner *****
2587a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner *****  L O O P E R
2597a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner *****
2607a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner **********************************************************************
2617a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner **********************************************************************/
2627a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
2637a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstruct GLooper {
2647a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    Looper       looper;
2657a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    ARefSet      timers[1];    /* set of all timers */
2667a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLoopTimer*  activeTimers; /* sorted list of active timers */
2677a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
2687a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    ARefSet      ios[1];        /* set of all i/o waiters */
2697a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    ARefSet      pendingIos[1]; /* list of pending i/o waiters */
2701bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner    int          numActiveIos;  /* number of active LoopIo objects */
2717a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
2727a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    IoLooper*    iolooper;
2737a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    int          running;
2747a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner};
2757a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
2767a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
2777a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerglooper_addTimer(GLooper* looper, GLoopTimer* tt)
2787a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
2797a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    arefSet_add(looper->timers, tt);
2807a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
2817a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
2827a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
2837a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerglooper_delTimer(GLooper* looper, GLoopTimer* tt)
2847a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
2857a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    arefSet_del(looper->timers, tt);
2867a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
2877a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
2887a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
2897a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerglooper_addActiveTimer(GLooper* looper, GLoopTimer* tt)
2907a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
2917a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    Duration  deadline = tt->deadline;
2927a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLoopTimer** pnode = &looper->activeTimers;
2937a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    for (;;) {
2947a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        GLoopTimer* node = *pnode;
2957a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        if (node == NULL || node->deadline > deadline)
2967a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            break;
2977a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        pnode = &node->activeNext;
2987a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    }
2997a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    tt->activeNext = *pnode;
30007db34976ba1dd045a51c4ab2c7f52479cddcc57David 'Digit' Turner    *pnode         = tt;
3017a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
3027a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
3037a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
3047a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerglooper_delActiveTimer(GLooper* looper, GLoopTimer* tt)
3057a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
3067a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLoopTimer** pnode = &looper->activeTimers;
3077a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    for (;;) {
3087a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        if (*pnode == NULL)
3097a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            break;
3107a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        if (*pnode == tt) {
3117a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            *pnode = tt->activeNext;
3127a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            tt->activeNext = NULL;
3137a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            break;
3147a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        }
3157a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        pnode = &(*pnode)->activeNext;
3167a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    }
3177a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
3187a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
3197a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
3207a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerglooper_addIo(GLooper* looper, GLoopIo* io)
3217a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
3227a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    arefSet_add(looper->ios, io);
3237a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
3247a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
3257a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
3267a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerglooper_delIo(GLooper* looper, GLoopIo* io)
3277a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
3287a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    arefSet_del(looper->ios, io);
3297a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
3307a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
3317a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
3327a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerglooper_delPendingIo(GLooper* looper, GLoopIo* io)
3337a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
3347a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    arefSet_del(looper->pendingIos, io);
3357a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
3367a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
3377a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
3387a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerglooper_modifyFd(GLooper* looper, int fd, int oldWanted, int newWanted)
3397a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
3401bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner    if (oldWanted == 0 && newWanted != 0)
3411bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner        looper->numActiveIos += 1;
3421bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner
3431bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner    if (oldWanted != 0 && newWanted == 0)
3441bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner        looper->numActiveIos -= 1;
3451bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner
3467a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    iolooper_modify(looper->iolooper, fd, oldWanted, newWanted);
3477a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
3487a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
3497a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic Duration
3507a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerglooper_now(Looper*  ll)
3517a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
3527a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    return iolooper_now();
3537a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
3547a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
3557a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
3567a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerglooper_forceQuit(Looper* ll)
3577a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
3587a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLooper*  looper = (GLooper*)ll;
3597a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    looper->running = 0;
3607a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
3617a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
3621bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turnerstatic int
3631bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turnerglooper_run(Looper*  ll, Duration loop_deadline_ms)
3647a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
3657a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLooper*   looper = (GLooper*) ll;
3667a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    IoLooper*  iol    = looper->iolooper;
3677a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
3687a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    looper->running = 1;
3697a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
3707a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    while (looper->running)
3717a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    {
3727a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        int ret;
3737a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
3741bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner        /* Exit prematurely if we detect that we don't have any active timer
3751bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner         * and no active LoopIo
3761bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner         */
3771bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner        if (looper->numActiveIos == 0 && looper->activeTimers == NULL)
3781bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner            return EWOULDBLOCK;
3791bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner
3807a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        /* First, compute next deadline */
3817a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        Duration  deadline = DURATION_INFINITE;
3827a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
3837a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        if (looper->activeTimers != NULL)
3847a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            deadline = looper->activeTimers->deadline;
3857a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
3861bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner        if (deadline > loop_deadline_ms)
3871bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner            deadline = loop_deadline_ms;
3881bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner
3897a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        ret = iolooper_wait_absolute(iol, deadline);
3907a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        if (ret < 0) { /* error, force stop ! */
3917a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            break;
3927a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        }
3937a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        if (ret > 0) {
3947a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            unsigned ready;
395347753be1d6bb07249641c84c3c582113af81941David 'Digit' Turner            GLoopIo* io;
3967a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
3977a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            /* Add io waiters to the pending list */
398347753be1d6bb07249641c84c3c582113af81941David 'Digit' Turner            AREFSET_FOREACH(looper->ios, io, {
3997a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                if (io->wanted == 0)
4007a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                    continue;
4017a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4027a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                ready = 0;
4037a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4047a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                if (iolooper_is_read(iol, io->fd))
4057a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                    ready |= LOOP_IO_READ;
4067a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4077a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                if (iolooper_is_write(iol, io->fd))
4087a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                    ready |= LOOP_IO_WRITE;
4097a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4107a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                io->ready = ready;
4117a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                if (ready != 0) {
4127a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                    arefSet_add(looper->pendingIos, io);
4137a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                }
4147a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            });
4157a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        }
4167a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4177a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        /* Do we have any expired timers here ? */
4187a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        GLoopTimer*  pendingTimers = NULL;
4197a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        GLoopTimer** pendingLastP  = &pendingTimers;
4207a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4217a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        deadline = iolooper_now();
4227a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        for (;;) {
4237a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            GLoopTimer*  timer = looper->activeTimers;
4247a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            if (timer == NULL || timer->deadline > deadline)
4257a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                break;
4267a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4277a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            /* remove from active list, and append to pending one */
4287a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            timer->deadline      = DURATION_INFINITE;
4297a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            looper->activeTimers = timer->activeNext;
4307a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4317a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            *pendingLastP     = timer;
4327a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            timer->activeNext = NULL;
4337a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            pendingLastP      = &timer->activeNext;
4347a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        }
4357a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4367a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        /* Fire the pending timers, if any. We do that in a separate
4377a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner         * step because the callbacks could modify the active list
4387a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner         * by starting/stopping other timers.
4397a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner         */
4407a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        {
4417a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            GLoopTimer*  timer;
4427a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            while ((timer = pendingTimers) != NULL) {
4437a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                pendingTimers     = timer->activeNext;
4447a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                timer->activeNext = NULL;
4457a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                timer->callback(timer->opaque);
4467a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            }
4477a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        }
4487a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4497a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        /* Now fire the pending ios */
4507a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        {
451347753be1d6bb07249641c84c3c582113af81941David 'Digit' Turner            GLoopIo* io;
452347753be1d6bb07249641c84c3c582113af81941David 'Digit' Turner            AREFSET_FOREACH(looper->pendingIos,io,{
4537a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner                io->callback(io->opaque,io->fd,io->ready);
4547a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            });
4557a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner            arefSet_clear(looper->pendingIos);
4567a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner        }
4571bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner
4581bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner        if (deadline > loop_deadline_ms)
4591bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner            return ETIMEDOUT;
4607a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    }
4611bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner    return 0;
4627a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
4637a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4647a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerstatic void
4657a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turnerglooper_free(Looper* ll)
4667a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
4677a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLooper* looper = (GLooper*)ll;
4687a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4697a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    arefSet_done(looper->timers);
4707a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    looper->activeTimers = NULL;
4717a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4727a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    arefSet_done(looper->ios);
4737a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    arefSet_done(looper->pendingIos);
4747a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4757a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    iolooper_free(looper->iolooper);
4767a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    looper->iolooper = NULL;
4777a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4787a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    AFREE(looper);
4797a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
4807a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4817a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' TurnerLooper*  looper_newGeneric(void)
4827a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner{
4837a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    GLooper*  looper;
4847a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4857a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    ANEW0(looper);
4867a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4871bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner    looper->iolooper = iolooper_new();
4881bb627cd086588d3f9650fac04f4034961caf9f1David 'Digit' Turner
4897a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    looper->looper.now        = glooper_now;
4907a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    looper->looper.timer_init = glooper_timer_init;
4917a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    looper->looper.io_init    = glooper_io_init;
4927a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    looper->looper.run        = glooper_run;
4937a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    looper->looper.forceQuit  = glooper_forceQuit;
4947a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    looper->looper.destroy    = glooper_free;
4957a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
4967a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    /* Our implementation depends on these values being equal */
4977a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    AASSERT_INT(LOOP_IO_READ,  IOLOOPER_READ);
4987a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    AASSERT_INT(LOOP_IO_WRITE, IOLOOPER_WRITE);
4997a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner
5007a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner    return &looper->looper;
5017a17b608de24e3aaf7d5ca030bb80a74dcc3baf9David 'Digit' Turner}
502