153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2004-2006 Lennart Poettering
553a5a1b3Sopenharmony_ci  Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
653a5a1b3Sopenharmony_ci
753a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
853a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as
953a5a1b3Sopenharmony_ci  published by the Free Software Foundation; either version 2.1 of the
1053a5a1b3Sopenharmony_ci  License, or (at your option) any later version.
1153a5a1b3Sopenharmony_ci
1253a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1353a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1453a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1553a5a1b3Sopenharmony_ci  Lesser General Public License for more details.
1653a5a1b3Sopenharmony_ci
1753a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public
1853a5a1b3Sopenharmony_ci  License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1953a5a1b3Sopenharmony_ci***/
2053a5a1b3Sopenharmony_ci
2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2253a5a1b3Sopenharmony_ci#include <config.h>
2353a5a1b3Sopenharmony_ci#endif
2453a5a1b3Sopenharmony_ci
2553a5a1b3Sopenharmony_ci#include <sys/types.h>
2653a5a1b3Sopenharmony_ci#include <stdio.h>
2753a5a1b3Sopenharmony_ci#include <string.h>
2853a5a1b3Sopenharmony_ci#include <errno.h>
2953a5a1b3Sopenharmony_ci
3053a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h>
3153a5a1b3Sopenharmony_ci#include <pulse/timeval.h>
3253a5a1b3Sopenharmony_ci
3353a5a1b3Sopenharmony_ci#include <pulsecore/poll.h>
3453a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h>
3553a5a1b3Sopenharmony_ci#include <pulsecore/core-rtclock.h>
3653a5a1b3Sopenharmony_ci#include <pulsecore/macro.h>
3753a5a1b3Sopenharmony_ci#include <pulsecore/llist.h>
3853a5a1b3Sopenharmony_ci#include <pulsecore/flist.h>
3953a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
4053a5a1b3Sopenharmony_ci#include <pulsecore/ratelimit.h>
4153a5a1b3Sopenharmony_ci#include <pulse/rtclock.h>
4253a5a1b3Sopenharmony_ci
4353a5a1b3Sopenharmony_ci#include "rtpoll.h"
4453a5a1b3Sopenharmony_ci#include "time.h"
4553a5a1b3Sopenharmony_ci
4653a5a1b3Sopenharmony_ci/* #define DEBUG_TIMING */
4753a5a1b3Sopenharmony_ci
4853a5a1b3Sopenharmony_cistruct pa_rtpoll {
4953a5a1b3Sopenharmony_ci    struct pollfd *pollfd, *pollfd2;
5053a5a1b3Sopenharmony_ci    unsigned n_pollfd_alloc, n_pollfd_used;
5153a5a1b3Sopenharmony_ci
5253a5a1b3Sopenharmony_ci    struct timeval next_elapse;
5353a5a1b3Sopenharmony_ci    bool timer_enabled:1;
5453a5a1b3Sopenharmony_ci
5553a5a1b3Sopenharmony_ci    bool scan_for_dead:1;
5653a5a1b3Sopenharmony_ci    bool running:1;
5753a5a1b3Sopenharmony_ci    bool rebuild_needed:1;
5853a5a1b3Sopenharmony_ci    bool quit:1;
5953a5a1b3Sopenharmony_ci    bool timer_elapsed:1;
6053a5a1b3Sopenharmony_ci
6153a5a1b3Sopenharmony_ci#ifdef DEBUG_TIMING
6253a5a1b3Sopenharmony_ci    pa_usec_t timestamp;
6353a5a1b3Sopenharmony_ci    pa_usec_t slept, awake;
6453a5a1b3Sopenharmony_ci#endif
6553a5a1b3Sopenharmony_ci
6653a5a1b3Sopenharmony_ci    PA_LLIST_HEAD(pa_rtpoll_item, items);
6753a5a1b3Sopenharmony_ci};
6853a5a1b3Sopenharmony_ci
6953a5a1b3Sopenharmony_cistruct pa_rtpoll_item {
7053a5a1b3Sopenharmony_ci    pa_rtpoll *rtpoll;
7153a5a1b3Sopenharmony_ci    bool dead;
7253a5a1b3Sopenharmony_ci
7353a5a1b3Sopenharmony_ci    pa_rtpoll_priority_t priority;
7453a5a1b3Sopenharmony_ci
7553a5a1b3Sopenharmony_ci    struct pollfd *pollfd;
7653a5a1b3Sopenharmony_ci    unsigned n_pollfd;
7753a5a1b3Sopenharmony_ci
7853a5a1b3Sopenharmony_ci    int (*work_cb)(pa_rtpoll_item *i);
7953a5a1b3Sopenharmony_ci    int (*before_cb)(pa_rtpoll_item *i);
8053a5a1b3Sopenharmony_ci    void (*after_cb)(pa_rtpoll_item *i);
8153a5a1b3Sopenharmony_ci    void *work_userdata;
8253a5a1b3Sopenharmony_ci    void *before_userdata;
8353a5a1b3Sopenharmony_ci    void *after_userdata;
8453a5a1b3Sopenharmony_ci
8553a5a1b3Sopenharmony_ci    PA_LLIST_FIELDS(pa_rtpoll_item);
8653a5a1b3Sopenharmony_ci};
8753a5a1b3Sopenharmony_ci
8853a5a1b3Sopenharmony_ciPA_STATIC_FLIST_DECLARE(items, 0, pa_xfree);
8953a5a1b3Sopenharmony_ci
9053a5a1b3Sopenharmony_cipa_rtpoll *pa_rtpoll_new(void) {
9153a5a1b3Sopenharmony_ci    pa_rtpoll *p;
9253a5a1b3Sopenharmony_ci
9353a5a1b3Sopenharmony_ci    p = pa_xnew0(pa_rtpoll, 1);
9453a5a1b3Sopenharmony_ci
9553a5a1b3Sopenharmony_ci    p->n_pollfd_alloc = 32;
9653a5a1b3Sopenharmony_ci    p->pollfd = pa_xnew(struct pollfd, p->n_pollfd_alloc);
9753a5a1b3Sopenharmony_ci    p->pollfd2 = pa_xnew(struct pollfd, p->n_pollfd_alloc);
9853a5a1b3Sopenharmony_ci
9953a5a1b3Sopenharmony_ci#ifdef DEBUG_TIMING
10053a5a1b3Sopenharmony_ci    p->timestamp = pa_rtclock_now();
10153a5a1b3Sopenharmony_ci#endif
10253a5a1b3Sopenharmony_ci
10353a5a1b3Sopenharmony_ci    return p;
10453a5a1b3Sopenharmony_ci}
10553a5a1b3Sopenharmony_ci
10653a5a1b3Sopenharmony_cistatic void rtpoll_rebuild(pa_rtpoll *p) {
10753a5a1b3Sopenharmony_ci
10853a5a1b3Sopenharmony_ci    struct pollfd *e, *t;
10953a5a1b3Sopenharmony_ci    pa_rtpoll_item *i;
11053a5a1b3Sopenharmony_ci    int ra = 0;
11153a5a1b3Sopenharmony_ci
11253a5a1b3Sopenharmony_ci    pa_assert(p);
11353a5a1b3Sopenharmony_ci
11453a5a1b3Sopenharmony_ci    p->rebuild_needed = false;
11553a5a1b3Sopenharmony_ci
11653a5a1b3Sopenharmony_ci    if (p->n_pollfd_used > p->n_pollfd_alloc) {
11753a5a1b3Sopenharmony_ci        /* Hmm, we have to allocate some more space */
11853a5a1b3Sopenharmony_ci        p->n_pollfd_alloc = p->n_pollfd_used * 2;
11953a5a1b3Sopenharmony_ci        p->pollfd2 = pa_xrealloc(p->pollfd2, p->n_pollfd_alloc * sizeof(struct pollfd));
12053a5a1b3Sopenharmony_ci        ra = 1;
12153a5a1b3Sopenharmony_ci    }
12253a5a1b3Sopenharmony_ci
12353a5a1b3Sopenharmony_ci    e = p->pollfd2;
12453a5a1b3Sopenharmony_ci
12553a5a1b3Sopenharmony_ci    for (i = p->items; i; i = i->next) {
12653a5a1b3Sopenharmony_ci
12753a5a1b3Sopenharmony_ci        if (i->n_pollfd > 0) {
12853a5a1b3Sopenharmony_ci            size_t l = i->n_pollfd * sizeof(struct pollfd);
12953a5a1b3Sopenharmony_ci
13053a5a1b3Sopenharmony_ci            if (i->pollfd)
13153a5a1b3Sopenharmony_ci                memcpy(e, i->pollfd, l);
13253a5a1b3Sopenharmony_ci            else
13353a5a1b3Sopenharmony_ci                memset(e, 0, l);
13453a5a1b3Sopenharmony_ci
13553a5a1b3Sopenharmony_ci            i->pollfd = e;
13653a5a1b3Sopenharmony_ci        } else
13753a5a1b3Sopenharmony_ci            i->pollfd = NULL;
13853a5a1b3Sopenharmony_ci
13953a5a1b3Sopenharmony_ci        e += i->n_pollfd;
14053a5a1b3Sopenharmony_ci    }
14153a5a1b3Sopenharmony_ci
14253a5a1b3Sopenharmony_ci    pa_assert((unsigned) (e - p->pollfd2) == p->n_pollfd_used);
14353a5a1b3Sopenharmony_ci    t = p->pollfd;
14453a5a1b3Sopenharmony_ci    p->pollfd = p->pollfd2;
14553a5a1b3Sopenharmony_ci    p->pollfd2 = t;
14653a5a1b3Sopenharmony_ci
14753a5a1b3Sopenharmony_ci    if (ra)
14853a5a1b3Sopenharmony_ci        p->pollfd2 = pa_xrealloc(p->pollfd2, p->n_pollfd_alloc * sizeof(struct pollfd));
14953a5a1b3Sopenharmony_ci}
15053a5a1b3Sopenharmony_ci
15153a5a1b3Sopenharmony_cistatic void rtpoll_item_destroy(pa_rtpoll_item *i) {
15253a5a1b3Sopenharmony_ci    pa_rtpoll *p;
15353a5a1b3Sopenharmony_ci
15453a5a1b3Sopenharmony_ci    pa_assert(i);
15553a5a1b3Sopenharmony_ci
15653a5a1b3Sopenharmony_ci    p = i->rtpoll;
15753a5a1b3Sopenharmony_ci
15853a5a1b3Sopenharmony_ci    PA_LLIST_REMOVE(pa_rtpoll_item, p->items, i);
15953a5a1b3Sopenharmony_ci
16053a5a1b3Sopenharmony_ci    p->n_pollfd_used -= i->n_pollfd;
16153a5a1b3Sopenharmony_ci
16253a5a1b3Sopenharmony_ci    if (pa_flist_push(PA_STATIC_FLIST_GET(items), i) < 0)
16353a5a1b3Sopenharmony_ci        pa_xfree(i);
16453a5a1b3Sopenharmony_ci
16553a5a1b3Sopenharmony_ci    p->rebuild_needed = true;
16653a5a1b3Sopenharmony_ci}
16753a5a1b3Sopenharmony_ci
16853a5a1b3Sopenharmony_civoid pa_rtpoll_free(pa_rtpoll *p) {
16953a5a1b3Sopenharmony_ci    pa_assert(p);
17053a5a1b3Sopenharmony_ci
17153a5a1b3Sopenharmony_ci    while (p->items)
17253a5a1b3Sopenharmony_ci        rtpoll_item_destroy(p->items);
17353a5a1b3Sopenharmony_ci
17453a5a1b3Sopenharmony_ci    pa_xfree(p->pollfd);
17553a5a1b3Sopenharmony_ci    pa_xfree(p->pollfd2);
17653a5a1b3Sopenharmony_ci
17753a5a1b3Sopenharmony_ci    pa_xfree(p);
17853a5a1b3Sopenharmony_ci}
17953a5a1b3Sopenharmony_ci
18053a5a1b3Sopenharmony_cistatic void reset_revents(pa_rtpoll_item *i) {
18153a5a1b3Sopenharmony_ci    struct pollfd *f;
18253a5a1b3Sopenharmony_ci    unsigned n;
18353a5a1b3Sopenharmony_ci
18453a5a1b3Sopenharmony_ci    pa_assert(i);
18553a5a1b3Sopenharmony_ci
18653a5a1b3Sopenharmony_ci    if (!(f = pa_rtpoll_item_get_pollfd(i, &n)))
18753a5a1b3Sopenharmony_ci        return;
18853a5a1b3Sopenharmony_ci
18953a5a1b3Sopenharmony_ci    for (; n > 0; n--)
19053a5a1b3Sopenharmony_ci        f[n-1].revents = 0;
19153a5a1b3Sopenharmony_ci}
19253a5a1b3Sopenharmony_ci
19353a5a1b3Sopenharmony_cistatic void reset_all_revents(pa_rtpoll *p) {
19453a5a1b3Sopenharmony_ci    pa_rtpoll_item *i;
19553a5a1b3Sopenharmony_ci
19653a5a1b3Sopenharmony_ci    pa_assert(p);
19753a5a1b3Sopenharmony_ci
19853a5a1b3Sopenharmony_ci    for (i = p->items; i; i = i->next) {
19953a5a1b3Sopenharmony_ci
20053a5a1b3Sopenharmony_ci        if (i->dead)
20153a5a1b3Sopenharmony_ci            continue;
20253a5a1b3Sopenharmony_ci
20353a5a1b3Sopenharmony_ci        reset_revents(i);
20453a5a1b3Sopenharmony_ci    }
20553a5a1b3Sopenharmony_ci}
20653a5a1b3Sopenharmony_ci
20753a5a1b3Sopenharmony_ciint pa_rtpoll_run(pa_rtpoll *p) {
20853a5a1b3Sopenharmony_ci    pa_rtpoll_item *i;
20953a5a1b3Sopenharmony_ci    int r = 0;
21053a5a1b3Sopenharmony_ci    struct timeval timeout;
21153a5a1b3Sopenharmony_ci
21253a5a1b3Sopenharmony_ci    pa_assert(p);
21353a5a1b3Sopenharmony_ci    pa_assert(!p->running);
21453a5a1b3Sopenharmony_ci
21553a5a1b3Sopenharmony_ci#ifdef DEBUG_TIMING
21653a5a1b3Sopenharmony_ci    pa_log("rtpoll_run");
21753a5a1b3Sopenharmony_ci#endif
21853a5a1b3Sopenharmony_ci
21953a5a1b3Sopenharmony_ci    p->running = true;
22053a5a1b3Sopenharmony_ci    p->timer_elapsed = false;
22153a5a1b3Sopenharmony_ci
22253a5a1b3Sopenharmony_ci    /* First, let's do some work */
22353a5a1b3Sopenharmony_ci    for (i = p->items; i && i->priority < PA_RTPOLL_NEVER; i = i->next) {
22453a5a1b3Sopenharmony_ci        int k;
22553a5a1b3Sopenharmony_ci
22653a5a1b3Sopenharmony_ci        if (i->dead)
22753a5a1b3Sopenharmony_ci            continue;
22853a5a1b3Sopenharmony_ci
22953a5a1b3Sopenharmony_ci        if (!i->work_cb)
23053a5a1b3Sopenharmony_ci            continue;
23153a5a1b3Sopenharmony_ci
23253a5a1b3Sopenharmony_ci        if (p->quit) {
23353a5a1b3Sopenharmony_ci#ifdef DEBUG_TIMING
23453a5a1b3Sopenharmony_ci            pa_log("rtpoll finish");
23553a5a1b3Sopenharmony_ci#endif
23653a5a1b3Sopenharmony_ci            goto finish;
23753a5a1b3Sopenharmony_ci        }
23853a5a1b3Sopenharmony_ci
23953a5a1b3Sopenharmony_ci        if ((k = i->work_cb(i)) != 0) {
24053a5a1b3Sopenharmony_ci            if (k < 0) {
24153a5a1b3Sopenharmony_ci                r = k;
24253a5a1b3Sopenharmony_ci                pa_log_error("Error %d in i->work_cb, goto finish", r);
24353a5a1b3Sopenharmony_ci            }
24453a5a1b3Sopenharmony_ci#ifdef DEBUG_TIMING
24553a5a1b3Sopenharmony_ci            pa_log("rtpoll finish");
24653a5a1b3Sopenharmony_ci#endif
24753a5a1b3Sopenharmony_ci            goto finish;
24853a5a1b3Sopenharmony_ci        }
24953a5a1b3Sopenharmony_ci    }
25053a5a1b3Sopenharmony_ci
25153a5a1b3Sopenharmony_ci    /* Now let's prepare for entering the sleep */
25253a5a1b3Sopenharmony_ci    for (i = p->items; i && i->priority < PA_RTPOLL_NEVER; i = i->next) {
25353a5a1b3Sopenharmony_ci        int k = 0;
25453a5a1b3Sopenharmony_ci
25553a5a1b3Sopenharmony_ci        if (i->dead)
25653a5a1b3Sopenharmony_ci            continue;
25753a5a1b3Sopenharmony_ci
25853a5a1b3Sopenharmony_ci        if (!i->before_cb)
25953a5a1b3Sopenharmony_ci            continue;
26053a5a1b3Sopenharmony_ci
26153a5a1b3Sopenharmony_ci        if (p->quit || (k = i->before_cb(i)) != 0) {
26253a5a1b3Sopenharmony_ci
26353a5a1b3Sopenharmony_ci            /* Hmm, this one doesn't let us enter the poll, so rewind everything */
26453a5a1b3Sopenharmony_ci
26553a5a1b3Sopenharmony_ci            for (i = i->prev; i; i = i->prev) {
26653a5a1b3Sopenharmony_ci
26753a5a1b3Sopenharmony_ci                if (i->dead)
26853a5a1b3Sopenharmony_ci                    continue;
26953a5a1b3Sopenharmony_ci
27053a5a1b3Sopenharmony_ci                if (!i->after_cb)
27153a5a1b3Sopenharmony_ci                    continue;
27253a5a1b3Sopenharmony_ci
27353a5a1b3Sopenharmony_ci                i->after_cb(i);
27453a5a1b3Sopenharmony_ci            }
27553a5a1b3Sopenharmony_ci
27653a5a1b3Sopenharmony_ci            if (k < 0) {
27753a5a1b3Sopenharmony_ci                pa_log_error("Error %d in i->before_cb, goto finish", r);
27853a5a1b3Sopenharmony_ci                r = k;
27953a5a1b3Sopenharmony_ci            }
28053a5a1b3Sopenharmony_ci#ifdef DEBUG_TIMING
28153a5a1b3Sopenharmony_ci            pa_log("rtpoll finish");
28253a5a1b3Sopenharmony_ci#endif
28353a5a1b3Sopenharmony_ci            goto finish;
28453a5a1b3Sopenharmony_ci        }
28553a5a1b3Sopenharmony_ci    }
28653a5a1b3Sopenharmony_ci
28753a5a1b3Sopenharmony_ci    if (p->rebuild_needed)
28853a5a1b3Sopenharmony_ci        rtpoll_rebuild(p);
28953a5a1b3Sopenharmony_ci
29053a5a1b3Sopenharmony_ci    pa_zero(timeout);
29153a5a1b3Sopenharmony_ci
29253a5a1b3Sopenharmony_ci    /* Calculate timeout */
29353a5a1b3Sopenharmony_ci    if (!p->quit && p->timer_enabled) {
29453a5a1b3Sopenharmony_ci        struct timeval now;
29553a5a1b3Sopenharmony_ci        pa_rtclock_get(&now);
29653a5a1b3Sopenharmony_ci
29753a5a1b3Sopenharmony_ci        if (pa_timeval_cmp(&p->next_elapse, &now) > 0)
29853a5a1b3Sopenharmony_ci            pa_timeval_add(&timeout, pa_timeval_diff(&p->next_elapse, &now));
29953a5a1b3Sopenharmony_ci    }
30053a5a1b3Sopenharmony_ci
30153a5a1b3Sopenharmony_ci#ifdef DEBUG_TIMING
30253a5a1b3Sopenharmony_ci    {
30353a5a1b3Sopenharmony_ci        pa_usec_t now = pa_rtclock_now();
30453a5a1b3Sopenharmony_ci        p->awake = now - p->timestamp;
30553a5a1b3Sopenharmony_ci        p->timestamp = now;
30653a5a1b3Sopenharmony_ci        if (!p->quit && p->timer_enabled)
30753a5a1b3Sopenharmony_ci            pa_log("poll timeout: %d ms ",(int) ((timeout.tv_sec*1000) + (timeout.tv_usec / 1000)));
30853a5a1b3Sopenharmony_ci        else if (p->quit)
30953a5a1b3Sopenharmony_ci            pa_log("poll timeout is ZERO");
31053a5a1b3Sopenharmony_ci        else
31153a5a1b3Sopenharmony_ci            pa_log("poll timeout is FOREVER");
31253a5a1b3Sopenharmony_ci    }
31353a5a1b3Sopenharmony_ci#endif
31453a5a1b3Sopenharmony_ci
31553a5a1b3Sopenharmony_ci    /* OK, now let's sleep */
31653a5a1b3Sopenharmony_ci#ifdef HAVE_PPOLL
31753a5a1b3Sopenharmony_ci    {
31853a5a1b3Sopenharmony_ci        struct timespec ts;
31953a5a1b3Sopenharmony_ci        ts.tv_sec = timeout.tv_sec;
32053a5a1b3Sopenharmony_ci        ts.tv_nsec = timeout.tv_usec * 1000;
32153a5a1b3Sopenharmony_ci        r = ppoll(p->pollfd, p->n_pollfd_used, (p->quit || p->timer_enabled) ? &ts : NULL, NULL);
32253a5a1b3Sopenharmony_ci    }
32353a5a1b3Sopenharmony_ci#else
32453a5a1b3Sopenharmony_ci    r = pa_poll(p->pollfd, p->n_pollfd_used, (p->quit || p->timer_enabled) ? (int) ((timeout.tv_sec*1000) + (timeout.tv_usec / 1000)) : -1);
32553a5a1b3Sopenharmony_ci#endif
32653a5a1b3Sopenharmony_ci
32753a5a1b3Sopenharmony_ci    p->timer_elapsed = r == 0;
32853a5a1b3Sopenharmony_ci
32953a5a1b3Sopenharmony_ci#ifdef DEBUG_TIMING
33053a5a1b3Sopenharmony_ci    {
33153a5a1b3Sopenharmony_ci        pa_usec_t now = pa_rtclock_now();
33253a5a1b3Sopenharmony_ci        p->slept = now - p->timestamp;
33353a5a1b3Sopenharmony_ci        p->timestamp = now;
33453a5a1b3Sopenharmony_ci
33553a5a1b3Sopenharmony_ci        pa_log("Process time %llu ms; sleep time %llu ms",
33653a5a1b3Sopenharmony_ci               (unsigned long long) (p->awake / PA_USEC_PER_MSEC),
33753a5a1b3Sopenharmony_ci               (unsigned long long) (p->slept / PA_USEC_PER_MSEC));
33853a5a1b3Sopenharmony_ci    }
33953a5a1b3Sopenharmony_ci#endif
34053a5a1b3Sopenharmony_ci
34153a5a1b3Sopenharmony_ci    if (r < 0) {
34253a5a1b3Sopenharmony_ci        if (errno == EAGAIN || errno == EINTR) {
34353a5a1b3Sopenharmony_ci            r = 0;
34453a5a1b3Sopenharmony_ci        } else {
34553a5a1b3Sopenharmony_ci            pa_log_error("Error %d in ppoll, errno: %s", r, pa_cstrerror(errno));
34653a5a1b3Sopenharmony_ci            pa_log_error("poll(): %s", pa_cstrerror(errno));
34753a5a1b3Sopenharmony_ci        }
34853a5a1b3Sopenharmony_ci
34953a5a1b3Sopenharmony_ci        reset_all_revents(p);
35053a5a1b3Sopenharmony_ci    }
35153a5a1b3Sopenharmony_ci
35253a5a1b3Sopenharmony_ci    /* Let's tell everyone that we left the sleep */
35353a5a1b3Sopenharmony_ci    for (i = p->items; i && i->priority < PA_RTPOLL_NEVER; i = i->next) {
35453a5a1b3Sopenharmony_ci
35553a5a1b3Sopenharmony_ci        if (i->dead)
35653a5a1b3Sopenharmony_ci            continue;
35753a5a1b3Sopenharmony_ci
35853a5a1b3Sopenharmony_ci        if (!i->after_cb)
35953a5a1b3Sopenharmony_ci            continue;
36053a5a1b3Sopenharmony_ci
36153a5a1b3Sopenharmony_ci        i->after_cb(i);
36253a5a1b3Sopenharmony_ci    }
36353a5a1b3Sopenharmony_ci
36453a5a1b3Sopenharmony_cifinish:
36553a5a1b3Sopenharmony_ci
36653a5a1b3Sopenharmony_ci    p->running = false;
36753a5a1b3Sopenharmony_ci
36853a5a1b3Sopenharmony_ci    if (p->scan_for_dead) {
36953a5a1b3Sopenharmony_ci        pa_rtpoll_item *n;
37053a5a1b3Sopenharmony_ci
37153a5a1b3Sopenharmony_ci        p->scan_for_dead = false;
37253a5a1b3Sopenharmony_ci
37353a5a1b3Sopenharmony_ci        for (i = p->items; i; i = n) {
37453a5a1b3Sopenharmony_ci            n = i->next;
37553a5a1b3Sopenharmony_ci
37653a5a1b3Sopenharmony_ci            if (i->dead)
37753a5a1b3Sopenharmony_ci                rtpoll_item_destroy(i);
37853a5a1b3Sopenharmony_ci        }
37953a5a1b3Sopenharmony_ci    }
38053a5a1b3Sopenharmony_ci
38153a5a1b3Sopenharmony_ci    return r < 0 ? r : !p->quit;
38253a5a1b3Sopenharmony_ci}
38353a5a1b3Sopenharmony_ci
38453a5a1b3Sopenharmony_civoid pa_rtpoll_set_timer_absolute(pa_rtpoll *p, pa_usec_t usec) {
38553a5a1b3Sopenharmony_ci    pa_assert(p);
38653a5a1b3Sopenharmony_ci
38753a5a1b3Sopenharmony_ci    pa_timeval_store(&p->next_elapse, usec);
38853a5a1b3Sopenharmony_ci    p->timer_enabled = true;
38953a5a1b3Sopenharmony_ci}
39053a5a1b3Sopenharmony_ci
39153a5a1b3Sopenharmony_civoid pa_rtpoll_set_timer_relative(pa_rtpoll *p, pa_usec_t usec) {
39253a5a1b3Sopenharmony_ci    pa_assert(p);
39353a5a1b3Sopenharmony_ci
39453a5a1b3Sopenharmony_ci    /* Scheduling a timeout for more than an hour is very very suspicious */
39553a5a1b3Sopenharmony_ci    pa_assert(usec <= PA_USEC_PER_SEC*60ULL*60ULL);
39653a5a1b3Sopenharmony_ci
39753a5a1b3Sopenharmony_ci    pa_rtclock_get(&p->next_elapse);
39853a5a1b3Sopenharmony_ci    pa_timeval_add(&p->next_elapse, usec);
39953a5a1b3Sopenharmony_ci    p->timer_enabled = true;
40053a5a1b3Sopenharmony_ci}
40153a5a1b3Sopenharmony_ci
40253a5a1b3Sopenharmony_civoid pa_rtpoll_set_timer_disabled(pa_rtpoll *p) {
40353a5a1b3Sopenharmony_ci    pa_assert(p);
40453a5a1b3Sopenharmony_ci
40553a5a1b3Sopenharmony_ci    memset(&p->next_elapse, 0, sizeof(p->next_elapse));
40653a5a1b3Sopenharmony_ci    p->timer_enabled = false;
40753a5a1b3Sopenharmony_ci}
40853a5a1b3Sopenharmony_ci
40953a5a1b3Sopenharmony_cipa_rtpoll_item *pa_rtpoll_item_new(pa_rtpoll *p, pa_rtpoll_priority_t prio, unsigned n_fds) {
41053a5a1b3Sopenharmony_ci    pa_rtpoll_item *i, *j, *l = NULL;
41153a5a1b3Sopenharmony_ci
41253a5a1b3Sopenharmony_ci    pa_assert(p);
41353a5a1b3Sopenharmony_ci
41453a5a1b3Sopenharmony_ci    if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items))))
41553a5a1b3Sopenharmony_ci        i = pa_xnew(pa_rtpoll_item, 1);
41653a5a1b3Sopenharmony_ci
41753a5a1b3Sopenharmony_ci    i->rtpoll = p;
41853a5a1b3Sopenharmony_ci    i->dead = false;
41953a5a1b3Sopenharmony_ci    i->n_pollfd = n_fds;
42053a5a1b3Sopenharmony_ci    i->pollfd = NULL;
42153a5a1b3Sopenharmony_ci    i->priority = prio;
42253a5a1b3Sopenharmony_ci
42353a5a1b3Sopenharmony_ci    i->work_userdata = NULL;
42453a5a1b3Sopenharmony_ci    i->before_userdata = NULL;
42553a5a1b3Sopenharmony_ci    i->work_userdata = NULL;
42653a5a1b3Sopenharmony_ci    i->before_cb = NULL;
42753a5a1b3Sopenharmony_ci    i->after_cb = NULL;
42853a5a1b3Sopenharmony_ci    i->work_cb = NULL;
42953a5a1b3Sopenharmony_ci
43053a5a1b3Sopenharmony_ci    for (j = p->items; j; j = j->next) {
43153a5a1b3Sopenharmony_ci        if (prio <= j->priority)
43253a5a1b3Sopenharmony_ci            break;
43353a5a1b3Sopenharmony_ci
43453a5a1b3Sopenharmony_ci        l = j;
43553a5a1b3Sopenharmony_ci    }
43653a5a1b3Sopenharmony_ci
43753a5a1b3Sopenharmony_ci    PA_LLIST_INSERT_AFTER(pa_rtpoll_item, p->items, j ? j->prev : l, i);
43853a5a1b3Sopenharmony_ci
43953a5a1b3Sopenharmony_ci    if (n_fds > 0) {
44053a5a1b3Sopenharmony_ci        p->rebuild_needed = 1;
44153a5a1b3Sopenharmony_ci        p->n_pollfd_used += n_fds;
44253a5a1b3Sopenharmony_ci    }
44353a5a1b3Sopenharmony_ci
44453a5a1b3Sopenharmony_ci    return i;
44553a5a1b3Sopenharmony_ci}
44653a5a1b3Sopenharmony_ci
44753a5a1b3Sopenharmony_civoid pa_rtpoll_item_free(pa_rtpoll_item *i) {
44853a5a1b3Sopenharmony_ci    pa_assert(i);
44953a5a1b3Sopenharmony_ci
45053a5a1b3Sopenharmony_ci    if (i->rtpoll->running) {
45153a5a1b3Sopenharmony_ci        i->dead = true;
45253a5a1b3Sopenharmony_ci        i->rtpoll->scan_for_dead = true;
45353a5a1b3Sopenharmony_ci        return;
45453a5a1b3Sopenharmony_ci    }
45553a5a1b3Sopenharmony_ci
45653a5a1b3Sopenharmony_ci    rtpoll_item_destroy(i);
45753a5a1b3Sopenharmony_ci}
45853a5a1b3Sopenharmony_ci
45953a5a1b3Sopenharmony_cistruct pollfd *pa_rtpoll_item_get_pollfd(pa_rtpoll_item *i, unsigned *n_fds) {
46053a5a1b3Sopenharmony_ci    pa_assert(i);
46153a5a1b3Sopenharmony_ci
46253a5a1b3Sopenharmony_ci    if (i->n_pollfd > 0)
46353a5a1b3Sopenharmony_ci        if (i->rtpoll->rebuild_needed)
46453a5a1b3Sopenharmony_ci            rtpoll_rebuild(i->rtpoll);
46553a5a1b3Sopenharmony_ci
46653a5a1b3Sopenharmony_ci    if (n_fds)
46753a5a1b3Sopenharmony_ci        *n_fds = i->n_pollfd;
46853a5a1b3Sopenharmony_ci
46953a5a1b3Sopenharmony_ci    return i->pollfd;
47053a5a1b3Sopenharmony_ci}
47153a5a1b3Sopenharmony_ci
47253a5a1b3Sopenharmony_civoid pa_rtpoll_item_set_before_callback(pa_rtpoll_item *i, int (*before_cb)(pa_rtpoll_item *i), void *userdata) {
47353a5a1b3Sopenharmony_ci    pa_assert(i);
47453a5a1b3Sopenharmony_ci    pa_assert(i->priority < PA_RTPOLL_NEVER);
47553a5a1b3Sopenharmony_ci
47653a5a1b3Sopenharmony_ci    i->before_cb = before_cb;
47753a5a1b3Sopenharmony_ci    i->before_userdata = userdata;
47853a5a1b3Sopenharmony_ci}
47953a5a1b3Sopenharmony_ci
48053a5a1b3Sopenharmony_civoid pa_rtpoll_item_set_after_callback(pa_rtpoll_item *i, void (*after_cb)(pa_rtpoll_item *i), void *userdata) {
48153a5a1b3Sopenharmony_ci    pa_assert(i);
48253a5a1b3Sopenharmony_ci    pa_assert(i->priority < PA_RTPOLL_NEVER);
48353a5a1b3Sopenharmony_ci
48453a5a1b3Sopenharmony_ci    i->after_cb = after_cb;
48553a5a1b3Sopenharmony_ci    i->after_userdata = userdata;
48653a5a1b3Sopenharmony_ci}
48753a5a1b3Sopenharmony_ci
48853a5a1b3Sopenharmony_civoid pa_rtpoll_item_set_work_callback(pa_rtpoll_item *i, int (*work_cb)(pa_rtpoll_item *i), void *userdata) {
48953a5a1b3Sopenharmony_ci    pa_assert(i);
49053a5a1b3Sopenharmony_ci    pa_assert(i->priority < PA_RTPOLL_NEVER);
49153a5a1b3Sopenharmony_ci
49253a5a1b3Sopenharmony_ci    i->work_cb = work_cb;
49353a5a1b3Sopenharmony_ci    i->work_userdata = userdata;
49453a5a1b3Sopenharmony_ci}
49553a5a1b3Sopenharmony_ci
49653a5a1b3Sopenharmony_civoid* pa_rtpoll_item_get_work_userdata(pa_rtpoll_item *i) {
49753a5a1b3Sopenharmony_ci    pa_assert(i);
49853a5a1b3Sopenharmony_ci
49953a5a1b3Sopenharmony_ci    return i->work_userdata;
50053a5a1b3Sopenharmony_ci}
50153a5a1b3Sopenharmony_ci
50253a5a1b3Sopenharmony_cistatic int fdsem_before(pa_rtpoll_item *i) {
50353a5a1b3Sopenharmony_ci
50453a5a1b3Sopenharmony_ci    if (pa_fdsem_before_poll(i->before_userdata) < 0)
50553a5a1b3Sopenharmony_ci        return 1; /* 1 means immediate restart of the loop */
50653a5a1b3Sopenharmony_ci
50753a5a1b3Sopenharmony_ci    return 0;
50853a5a1b3Sopenharmony_ci}
50953a5a1b3Sopenharmony_ci
51053a5a1b3Sopenharmony_cistatic void fdsem_after(pa_rtpoll_item *i) {
51153a5a1b3Sopenharmony_ci    pa_assert(i);
51253a5a1b3Sopenharmony_ci
51353a5a1b3Sopenharmony_ci    pa_assert((i->pollfd[0].revents & ~POLLIN) == 0);
51453a5a1b3Sopenharmony_ci    pa_fdsem_after_poll(i->after_userdata);
51553a5a1b3Sopenharmony_ci}
51653a5a1b3Sopenharmony_ci
51753a5a1b3Sopenharmony_cipa_rtpoll_item *pa_rtpoll_item_new_fdsem(pa_rtpoll *p, pa_rtpoll_priority_t prio, pa_fdsem *f) {
51853a5a1b3Sopenharmony_ci    pa_rtpoll_item *i;
51953a5a1b3Sopenharmony_ci    struct pollfd *pollfd;
52053a5a1b3Sopenharmony_ci
52153a5a1b3Sopenharmony_ci    pa_assert(p);
52253a5a1b3Sopenharmony_ci    pa_assert(f);
52353a5a1b3Sopenharmony_ci
52453a5a1b3Sopenharmony_ci    i = pa_rtpoll_item_new(p, prio, 1);
52553a5a1b3Sopenharmony_ci
52653a5a1b3Sopenharmony_ci    pollfd = pa_rtpoll_item_get_pollfd(i, NULL);
52753a5a1b3Sopenharmony_ci
52853a5a1b3Sopenharmony_ci    pollfd->fd = pa_fdsem_get(f);
52953a5a1b3Sopenharmony_ci    pollfd->events = POLLIN;
53053a5a1b3Sopenharmony_ci
53153a5a1b3Sopenharmony_ci    pa_rtpoll_item_set_before_callback(i, fdsem_before, f);
53253a5a1b3Sopenharmony_ci    pa_rtpoll_item_set_after_callback(i, fdsem_after, f);
53353a5a1b3Sopenharmony_ci
53453a5a1b3Sopenharmony_ci    return i;
53553a5a1b3Sopenharmony_ci}
53653a5a1b3Sopenharmony_ci
53753a5a1b3Sopenharmony_cistatic int asyncmsgq_read_before(pa_rtpoll_item *i) {
53853a5a1b3Sopenharmony_ci    pa_assert(i);
53953a5a1b3Sopenharmony_ci
54053a5a1b3Sopenharmony_ci    if (pa_asyncmsgq_read_before_poll(i->before_userdata) < 0)
54153a5a1b3Sopenharmony_ci        return 1; /* 1 means immediate restart of the loop */
54253a5a1b3Sopenharmony_ci
54353a5a1b3Sopenharmony_ci    return 0;
54453a5a1b3Sopenharmony_ci}
54553a5a1b3Sopenharmony_ci
54653a5a1b3Sopenharmony_cistatic void asyncmsgq_read_after(pa_rtpoll_item *i) {
54753a5a1b3Sopenharmony_ci    pa_assert(i);
54853a5a1b3Sopenharmony_ci
54953a5a1b3Sopenharmony_ci    pa_assert((i->pollfd[0].revents & ~POLLIN) == 0);
55053a5a1b3Sopenharmony_ci    pa_asyncmsgq_read_after_poll(i->after_userdata);
55153a5a1b3Sopenharmony_ci}
55253a5a1b3Sopenharmony_ci
55353a5a1b3Sopenharmony_cistatic int asyncmsgq_read_work(pa_rtpoll_item *i) {
55453a5a1b3Sopenharmony_ci    pa_msgobject *object;
55553a5a1b3Sopenharmony_ci    int code;
55653a5a1b3Sopenharmony_ci    void *data;
55753a5a1b3Sopenharmony_ci    pa_memchunk chunk;
55853a5a1b3Sopenharmony_ci    int64_t offset;
55953a5a1b3Sopenharmony_ci
56053a5a1b3Sopenharmony_ci    pa_assert(i);
56153a5a1b3Sopenharmony_ci
56253a5a1b3Sopenharmony_ci    if (pa_asyncmsgq_get(i->work_userdata, &object, &code, &data, &offset, &chunk, 0) == 0) {
56353a5a1b3Sopenharmony_ci        int ret;
56453a5a1b3Sopenharmony_ci
56553a5a1b3Sopenharmony_ci        if (!object && code == PA_MESSAGE_SHUTDOWN) {
56653a5a1b3Sopenharmony_ci            pa_asyncmsgq_done(i->work_userdata, 0);
56753a5a1b3Sopenharmony_ci            /* Requests the loop to exit. Will cause the next iteration of
56853a5a1b3Sopenharmony_ci             * pa_rtpoll_run() to return 0 */
56953a5a1b3Sopenharmony_ci            i->rtpoll->quit = true;
57053a5a1b3Sopenharmony_ci            return 1;
57153a5a1b3Sopenharmony_ci        }
57253a5a1b3Sopenharmony_ci
57353a5a1b3Sopenharmony_ci        clock_t start = clock();
57453a5a1b3Sopenharmony_ci        ret = pa_asyncmsgq_dispatch(object, code, data, offset, &chunk);
57553a5a1b3Sopenharmony_ci        clock_t end = clock();
57653a5a1b3Sopenharmony_ci        double deltatime = (double)(end - start) / CLOCKS_PER_SEC;
57753a5a1b3Sopenharmony_ci        if (deltatime > 1.0) {
57853a5a1b3Sopenharmony_ci            pa_log_error("code %d time out %f s", code, deltatime);
57953a5a1b3Sopenharmony_ci        }
58053a5a1b3Sopenharmony_ci        pa_asyncmsgq_done(i->work_userdata, ret);
58153a5a1b3Sopenharmony_ci        return 1;
58253a5a1b3Sopenharmony_ci    }
58353a5a1b3Sopenharmony_ci
58453a5a1b3Sopenharmony_ci    return 0;
58553a5a1b3Sopenharmony_ci}
58653a5a1b3Sopenharmony_ci
58753a5a1b3Sopenharmony_cipa_rtpoll_item *pa_rtpoll_item_new_asyncmsgq_read(pa_rtpoll *p, pa_rtpoll_priority_t prio, pa_asyncmsgq *q) {
58853a5a1b3Sopenharmony_ci    pa_rtpoll_item *i;
58953a5a1b3Sopenharmony_ci    struct pollfd *pollfd;
59053a5a1b3Sopenharmony_ci
59153a5a1b3Sopenharmony_ci    pa_assert(p);
59253a5a1b3Sopenharmony_ci    pa_assert(q);
59353a5a1b3Sopenharmony_ci
59453a5a1b3Sopenharmony_ci    i = pa_rtpoll_item_new(p, prio, 1);
59553a5a1b3Sopenharmony_ci
59653a5a1b3Sopenharmony_ci    pollfd = pa_rtpoll_item_get_pollfd(i, NULL);
59753a5a1b3Sopenharmony_ci    pollfd->fd = pa_asyncmsgq_read_fd(q);
59853a5a1b3Sopenharmony_ci    pollfd->events = POLLIN;
59953a5a1b3Sopenharmony_ci
60053a5a1b3Sopenharmony_ci    pa_rtpoll_item_set_before_callback(i, asyncmsgq_read_before, q);
60153a5a1b3Sopenharmony_ci    pa_rtpoll_item_set_after_callback(i, asyncmsgq_read_after, q);
60253a5a1b3Sopenharmony_ci    pa_rtpoll_item_set_work_callback(i, asyncmsgq_read_work, q);
60353a5a1b3Sopenharmony_ci
60453a5a1b3Sopenharmony_ci    return i;
60553a5a1b3Sopenharmony_ci}
60653a5a1b3Sopenharmony_ci
60753a5a1b3Sopenharmony_cistatic int asyncmsgq_write_before(pa_rtpoll_item *i) {
60853a5a1b3Sopenharmony_ci    pa_assert(i);
60953a5a1b3Sopenharmony_ci
61053a5a1b3Sopenharmony_ci    pa_asyncmsgq_write_before_poll(i->before_userdata);
61153a5a1b3Sopenharmony_ci    return 0;
61253a5a1b3Sopenharmony_ci}
61353a5a1b3Sopenharmony_ci
61453a5a1b3Sopenharmony_cistatic void asyncmsgq_write_after(pa_rtpoll_item *i) {
61553a5a1b3Sopenharmony_ci    pa_assert(i);
61653a5a1b3Sopenharmony_ci
61753a5a1b3Sopenharmony_ci    pa_assert((i->pollfd[0].revents & ~POLLIN) == 0);
61853a5a1b3Sopenharmony_ci    pa_asyncmsgq_write_after_poll(i->after_userdata);
61953a5a1b3Sopenharmony_ci}
62053a5a1b3Sopenharmony_ci
62153a5a1b3Sopenharmony_cipa_rtpoll_item *pa_rtpoll_item_new_asyncmsgq_write(pa_rtpoll *p, pa_rtpoll_priority_t prio, pa_asyncmsgq *q) {
62253a5a1b3Sopenharmony_ci    pa_rtpoll_item *i;
62353a5a1b3Sopenharmony_ci    struct pollfd *pollfd;
62453a5a1b3Sopenharmony_ci
62553a5a1b3Sopenharmony_ci    pa_assert(p);
62653a5a1b3Sopenharmony_ci    pa_assert(q);
62753a5a1b3Sopenharmony_ci
62853a5a1b3Sopenharmony_ci    i = pa_rtpoll_item_new(p, prio, 1);
62953a5a1b3Sopenharmony_ci
63053a5a1b3Sopenharmony_ci    pollfd = pa_rtpoll_item_get_pollfd(i, NULL);
63153a5a1b3Sopenharmony_ci    pollfd->fd = pa_asyncmsgq_write_fd(q);
63253a5a1b3Sopenharmony_ci    pollfd->events = POLLIN;
63353a5a1b3Sopenharmony_ci
63453a5a1b3Sopenharmony_ci    pa_rtpoll_item_set_before_callback(i, asyncmsgq_write_before, q);
63553a5a1b3Sopenharmony_ci    pa_rtpoll_item_set_after_callback(i, asyncmsgq_write_after, q);
63653a5a1b3Sopenharmony_ci
63753a5a1b3Sopenharmony_ci    return i;
63853a5a1b3Sopenharmony_ci}
63953a5a1b3Sopenharmony_ci
64053a5a1b3Sopenharmony_cibool pa_rtpoll_timer_elapsed(pa_rtpoll *p) {
64153a5a1b3Sopenharmony_ci    pa_assert(p);
64253a5a1b3Sopenharmony_ci
64353a5a1b3Sopenharmony_ci    return p->timer_elapsed;
64453a5a1b3Sopenharmony_ci}
645