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