2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 #include <sys/types.h>
33 #include <pulse/xmalloc.h>
34 #include <pulse/timeval.h>
36 #include <pulsecore/poll.h>
37 #include <pulsecore/core-error.h>
38 #include <pulsecore/core-rtclock.h>
39 #include <pulsecore/macro.h>
40 #include <pulsecore/llist.h>
41 #include <pulsecore/flist.h>
42 #include <pulsecore/core-util.h>
43 #include <pulsecore/ratelimit.h>
44 #include <pulse/rtclock.h>
48 /* #define DEBUG_TIMING */
51 struct pollfd
*pollfd
, *pollfd2
;
52 unsigned n_pollfd_alloc
, n_pollfd_used
;
54 struct timeval next_elapse
;
55 pa_bool_t timer_enabled
:1;
57 pa_bool_t scan_for_dead
:1;
59 pa_bool_t rebuild_needed
:1;
61 pa_bool_t timer_elapsed
:1;
65 pa_usec_t slept
, awake
;
68 PA_LLIST_HEAD(pa_rtpoll_item
, items
);
71 struct pa_rtpoll_item
{
75 pa_rtpoll_priority_t priority
;
77 struct pollfd
*pollfd
;
80 int (*work_cb
)(pa_rtpoll_item
*i
);
81 int (*before_cb
)(pa_rtpoll_item
*i
);
82 void (*after_cb
)(pa_rtpoll_item
*i
);
85 PA_LLIST_FIELDS(pa_rtpoll_item
);
88 PA_STATIC_FLIST_DECLARE(items
, 0, pa_xfree
);
90 pa_rtpoll
*pa_rtpoll_new(void) {
93 p
= pa_xnew0(pa_rtpoll
, 1);
95 p
->n_pollfd_alloc
= 32;
96 p
->pollfd
= pa_xnew(struct pollfd
, p
->n_pollfd_alloc
);
97 p
->pollfd2
= pa_xnew(struct pollfd
, p
->n_pollfd_alloc
);
100 p
->timestamp
= pa_rtclock_now();
106 static void rtpoll_rebuild(pa_rtpoll
*p
) {
108 struct pollfd
*e
, *t
;
114 p
->rebuild_needed
= FALSE
;
116 if (p
->n_pollfd_used
> p
->n_pollfd_alloc
) {
117 /* Hmm, we have to allocate some more space */
118 p
->n_pollfd_alloc
= p
->n_pollfd_used
* 2;
119 p
->pollfd2
= pa_xrealloc(p
->pollfd2
, p
->n_pollfd_alloc
* sizeof(struct pollfd
));
125 for (i
= p
->items
; i
; i
= i
->next
) {
127 if (i
->n_pollfd
> 0) {
128 size_t l
= i
->n_pollfd
* sizeof(struct pollfd
);
131 memcpy(e
, i
->pollfd
, l
);
142 pa_assert((unsigned) (e
- p
->pollfd2
) == p
->n_pollfd_used
);
144 p
->pollfd
= p
->pollfd2
;
148 p
->pollfd2
= pa_xrealloc(p
->pollfd2
, p
->n_pollfd_alloc
* sizeof(struct pollfd
));
151 static void rtpoll_item_destroy(pa_rtpoll_item
*i
) {
158 PA_LLIST_REMOVE(pa_rtpoll_item
, p
->items
, i
);
160 p
->n_pollfd_used
-= i
->n_pollfd
;
162 if (pa_flist_push(PA_STATIC_FLIST_GET(items
), i
) < 0)
165 p
->rebuild_needed
= TRUE
;
168 void pa_rtpoll_free(pa_rtpoll
*p
) {
172 rtpoll_item_destroy(p
->items
);
175 pa_xfree(p
->pollfd2
);
180 static void reset_revents(pa_rtpoll_item
*i
) {
186 if (!(f
= pa_rtpoll_item_get_pollfd(i
, &n
)))
193 static void reset_all_revents(pa_rtpoll
*p
) {
198 for (i
= p
->items
; i
; i
= i
->next
) {
207 int pa_rtpoll_run(pa_rtpoll
*p
, pa_bool_t wait_op
) {
210 struct timeval timeout
;
213 pa_assert(!p
->running
);
216 pa_log("rtpoll_run");
220 p
->timer_elapsed
= FALSE
;
222 /* First, let's do some work */
223 for (i
= p
->items
; i
&& i
->priority
< PA_RTPOLL_NEVER
; i
= i
->next
) {
234 pa_log("rtpoll finish");
239 if ((k
= i
->work_cb(i
)) != 0) {
243 pa_log("rtpoll finish");
249 /* Now let's prepare for entering the sleep */
250 for (i
= p
->items
; i
&& i
->priority
< PA_RTPOLL_NEVER
; i
= i
->next
) {
259 if (p
->quit
|| (k
= i
->before_cb(i
)) != 0) {
261 /* Hmm, this one doesn't let us enter the poll, so rewind everything */
263 for (i
= i
->prev
; i
; i
= i
->prev
) {
277 pa_log("rtpoll finish");
283 if (p
->rebuild_needed
)
288 /* Calculate timeout */
289 if (wait_op
&& !p
->quit
&& p
->timer_enabled
) {
291 pa_rtclock_get(&now
);
293 if (pa_timeval_cmp(&p
->next_elapse
, &now
) > 0)
294 pa_timeval_add(&timeout
, pa_timeval_diff(&p
->next_elapse
, &now
));
299 pa_usec_t now
= pa_rtclock_now();
300 p
->awake
= now
- p
->timestamp
;
302 if (!wait_op
|| p
->quit
|| p
->timer_enabled
)
303 pa_log("poll timeout: %d ms ",(int) ((timeout
.tv_sec
*1000) + (timeout
.tv_usec
/ 1000)));
305 pa_log("poll timeout is ZERO");
309 /* OK, now let's sleep */
313 ts
.tv_sec
= timeout
.tv_sec
;
314 ts
.tv_nsec
= timeout
.tv_usec
* 1000;
315 r
= ppoll(p
->pollfd
, p
->n_pollfd_used
, (!wait_op
|| p
->quit
|| p
->timer_enabled
) ? &ts
: NULL
, NULL
);
318 r
= pa_poll(p
->pollfd
, p
->n_pollfd_used
, (!wait_op
|| p
->quit
|| p
->timer_enabled
) ? (int) ((timeout
.tv_sec
*1000) + (timeout
.tv_usec
/ 1000)) : -1);
321 p
->timer_elapsed
= r
== 0;
325 pa_usec_t now
= pa_rtclock_now();
326 p
->slept
= now
- p
->timestamp
;
329 pa_log("Process time %llu ms; sleep time %llu ms",
330 (unsigned long long) (p
->awake
/ PA_USEC_PER_MSEC
),
331 (unsigned long long) (p
->slept
/ PA_USEC_PER_MSEC
));
336 if (errno
== EAGAIN
|| errno
== EINTR
)
339 pa_log_error("poll(): %s", pa_cstrerror(errno
));
341 reset_all_revents(p
);
344 /* Let's tell everyone that we left the sleep */
345 for (i
= p
->items
; i
&& i
->priority
< PA_RTPOLL_NEVER
; i
= i
->next
) {
360 if (p
->scan_for_dead
) {
363 p
->scan_for_dead
= FALSE
;
365 for (i
= p
->items
; i
; i
= n
) {
369 rtpoll_item_destroy(i
);
373 return r
< 0 ? r
: !p
->quit
;
376 void pa_rtpoll_set_timer_absolute(pa_rtpoll
*p
, pa_usec_t usec
) {
379 pa_timeval_store(&p
->next_elapse
, usec
);
380 p
->timer_enabled
= TRUE
;
383 void pa_rtpoll_set_timer_relative(pa_rtpoll
*p
, pa_usec_t usec
) {
386 /* Scheduling a timeout for more than an hour is very very suspicious */
387 pa_assert(usec
<= PA_USEC_PER_SEC
*60ULL*60ULL);
389 pa_rtclock_get(&p
->next_elapse
);
390 pa_timeval_add(&p
->next_elapse
, usec
);
391 p
->timer_enabled
= TRUE
;
394 void pa_rtpoll_set_timer_disabled(pa_rtpoll
*p
) {
397 memset(&p
->next_elapse
, 0, sizeof(p
->next_elapse
));
398 p
->timer_enabled
= FALSE
;
401 pa_rtpoll_item
*pa_rtpoll_item_new(pa_rtpoll
*p
, pa_rtpoll_priority_t prio
, unsigned n_fds
) {
402 pa_rtpoll_item
*i
, *j
, *l
= NULL
;
406 if (!(i
= pa_flist_pop(PA_STATIC_FLIST_GET(items
))))
407 i
= pa_xnew(pa_rtpoll_item
, 1);
420 for (j
= p
->items
; j
; j
= j
->next
) {
421 if (prio
<= j
->priority
)
427 PA_LLIST_INSERT_AFTER(pa_rtpoll_item
, p
->items
, j
? j
->prev
: l
, i
);
430 p
->rebuild_needed
= 1;
431 p
->n_pollfd_used
+= n_fds
;
437 void pa_rtpoll_item_free(pa_rtpoll_item
*i
) {
440 if (i
->rtpoll
->running
) {
442 i
->rtpoll
->scan_for_dead
= TRUE
;
446 rtpoll_item_destroy(i
);
449 struct pollfd
*pa_rtpoll_item_get_pollfd(pa_rtpoll_item
*i
, unsigned *n_fds
) {
453 if (i
->rtpoll
->rebuild_needed
)
454 rtpoll_rebuild(i
->rtpoll
);
457 *n_fds
= i
->n_pollfd
;
462 void pa_rtpoll_item_set_before_callback(pa_rtpoll_item
*i
, int (*before_cb
)(pa_rtpoll_item
*i
)) {
464 pa_assert(i
->priority
< PA_RTPOLL_NEVER
);
466 i
->before_cb
= before_cb
;
469 void pa_rtpoll_item_set_after_callback(pa_rtpoll_item
*i
, void (*after_cb
)(pa_rtpoll_item
*i
)) {
471 pa_assert(i
->priority
< PA_RTPOLL_NEVER
);
473 i
->after_cb
= after_cb
;
476 void pa_rtpoll_item_set_work_callback(pa_rtpoll_item
*i
, int (*work_cb
)(pa_rtpoll_item
*i
)) {
478 pa_assert(i
->priority
< PA_RTPOLL_NEVER
);
480 i
->work_cb
= work_cb
;
483 void pa_rtpoll_item_set_userdata(pa_rtpoll_item
*i
, void *userdata
) {
486 i
->userdata
= userdata
;
489 void* pa_rtpoll_item_get_userdata(pa_rtpoll_item
*i
) {
495 static int fdsem_before(pa_rtpoll_item
*i
) {
497 if (pa_fdsem_before_poll(i
->userdata
) < 0)
498 return 1; /* 1 means immediate restart of the loop */
503 static void fdsem_after(pa_rtpoll_item
*i
) {
506 pa_assert((i
->pollfd
[0].revents
& ~POLLIN
) == 0);
507 pa_fdsem_after_poll(i
->userdata
);
510 pa_rtpoll_item
*pa_rtpoll_item_new_fdsem(pa_rtpoll
*p
, pa_rtpoll_priority_t prio
, pa_fdsem
*f
) {
512 struct pollfd
*pollfd
;
517 i
= pa_rtpoll_item_new(p
, prio
, 1);
519 pollfd
= pa_rtpoll_item_get_pollfd(i
, NULL
);
521 pollfd
->fd
= pa_fdsem_get(f
);
522 pollfd
->events
= POLLIN
;
524 i
->before_cb
= fdsem_before
;
525 i
->after_cb
= fdsem_after
;
531 static int asyncmsgq_read_before(pa_rtpoll_item
*i
) {
534 if (pa_asyncmsgq_read_before_poll(i
->userdata
) < 0)
535 return 1; /* 1 means immediate restart of the loop */
540 static void asyncmsgq_read_after(pa_rtpoll_item
*i
) {
543 pa_assert((i
->pollfd
[0].revents
& ~POLLIN
) == 0);
544 pa_asyncmsgq_read_after_poll(i
->userdata
);
547 static int asyncmsgq_read_work(pa_rtpoll_item
*i
) {
548 pa_msgobject
*object
;
556 if (pa_asyncmsgq_get(i
->userdata
, &object
, &code
, &data
, &offset
, &chunk
, 0) == 0) {
559 if (!object
&& code
== PA_MESSAGE_SHUTDOWN
) {
560 pa_asyncmsgq_done(i
->userdata
, 0);
561 pa_rtpoll_quit(i
->rtpoll
);
565 ret
= pa_asyncmsgq_dispatch(object
, code
, data
, offset
, &chunk
);
566 pa_asyncmsgq_done(i
->userdata
, ret
);
573 pa_rtpoll_item
*pa_rtpoll_item_new_asyncmsgq_read(pa_rtpoll
*p
, pa_rtpoll_priority_t prio
, pa_asyncmsgq
*q
) {
575 struct pollfd
*pollfd
;
580 i
= pa_rtpoll_item_new(p
, prio
, 1);
582 pollfd
= pa_rtpoll_item_get_pollfd(i
, NULL
);
583 pollfd
->fd
= pa_asyncmsgq_read_fd(q
);
584 pollfd
->events
= POLLIN
;
586 i
->before_cb
= asyncmsgq_read_before
;
587 i
->after_cb
= asyncmsgq_read_after
;
588 i
->work_cb
= asyncmsgq_read_work
;
594 static int asyncmsgq_write_before(pa_rtpoll_item
*i
) {
597 pa_asyncmsgq_write_before_poll(i
->userdata
);
601 static void asyncmsgq_write_after(pa_rtpoll_item
*i
) {
604 pa_assert((i
->pollfd
[0].revents
& ~POLLIN
) == 0);
605 pa_asyncmsgq_write_after_poll(i
->userdata
);
608 pa_rtpoll_item
*pa_rtpoll_item_new_asyncmsgq_write(pa_rtpoll
*p
, pa_rtpoll_priority_t prio
, pa_asyncmsgq
*q
) {
610 struct pollfd
*pollfd
;
615 i
= pa_rtpoll_item_new(p
, prio
, 1);
617 pollfd
= pa_rtpoll_item_get_pollfd(i
, NULL
);
618 pollfd
->fd
= pa_asyncmsgq_write_fd(q
);
619 pollfd
->events
= POLLIN
;
621 i
->before_cb
= asyncmsgq_write_before
;
622 i
->after_cb
= asyncmsgq_write_after
;
629 void pa_rtpoll_quit(pa_rtpoll
*p
) {
635 pa_bool_t
pa_rtpoll_timer_elapsed(pa_rtpoll
*p
) {
638 return p
->timer_elapsed
;