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>
32 #include <pulse/xmalloc.h>
33 #include <pulse/timeval.h>
35 #include <pulsecore/poll.h>
36 #include <pulsecore/core-error.h>
37 #include <pulsecore/core-rtclock.h>
38 #include <pulsecore/macro.h>
39 #include <pulsecore/llist.h>
40 #include <pulsecore/flist.h>
41 #include <pulsecore/core-util.h>
42 #include <pulsecore/ratelimit.h>
43 #include <pulse/rtclock.h>
47 /* #define DEBUG_TIMING */
50 struct pollfd
*pollfd
, *pollfd2
;
51 unsigned n_pollfd_alloc
, n_pollfd_used
;
53 struct timeval next_elapse
;
54 pa_bool_t timer_enabled
:1;
56 pa_bool_t scan_for_dead
:1;
58 pa_bool_t rebuild_needed
:1;
60 pa_bool_t timer_elapsed
:1;
64 pa_usec_t slept
, awake
;
67 PA_LLIST_HEAD(pa_rtpoll_item
, items
);
70 struct pa_rtpoll_item
{
74 pa_rtpoll_priority_t priority
;
76 struct pollfd
*pollfd
;
79 int (*work_cb
)(pa_rtpoll_item
*i
);
80 int (*before_cb
)(pa_rtpoll_item
*i
);
81 void (*after_cb
)(pa_rtpoll_item
*i
);
84 PA_LLIST_FIELDS(pa_rtpoll_item
);
87 PA_STATIC_FLIST_DECLARE(items
, 0, pa_xfree
);
89 pa_rtpoll
*pa_rtpoll_new(void) {
92 p
= pa_xnew0(pa_rtpoll
, 1);
94 p
->n_pollfd_alloc
= 32;
95 p
->pollfd
= pa_xnew(struct pollfd
, p
->n_pollfd_alloc
);
96 p
->pollfd2
= pa_xnew(struct pollfd
, p
->n_pollfd_alloc
);
99 p
->timestamp
= pa_rtclock_now();
105 static void rtpoll_rebuild(pa_rtpoll
*p
) {
107 struct pollfd
*e
, *t
;
113 p
->rebuild_needed
= FALSE
;
115 if (p
->n_pollfd_used
> p
->n_pollfd_alloc
) {
116 /* Hmm, we have to allocate some more space */
117 p
->n_pollfd_alloc
= p
->n_pollfd_used
* 2;
118 p
->pollfd2
= pa_xrealloc(p
->pollfd2
, p
->n_pollfd_alloc
* sizeof(struct pollfd
));
124 for (i
= p
->items
; i
; i
= i
->next
) {
126 if (i
->n_pollfd
> 0) {
127 size_t l
= i
->n_pollfd
* sizeof(struct pollfd
);
130 memcpy(e
, i
->pollfd
, l
);
141 pa_assert((unsigned) (e
- p
->pollfd2
) == p
->n_pollfd_used
);
143 p
->pollfd
= p
->pollfd2
;
147 p
->pollfd2
= pa_xrealloc(p
->pollfd2
, p
->n_pollfd_alloc
* sizeof(struct pollfd
));
150 static void rtpoll_item_destroy(pa_rtpoll_item
*i
) {
157 PA_LLIST_REMOVE(pa_rtpoll_item
, p
->items
, i
);
159 p
->n_pollfd_used
-= i
->n_pollfd
;
161 if (pa_flist_push(PA_STATIC_FLIST_GET(items
), i
) < 0)
164 p
->rebuild_needed
= TRUE
;
167 void pa_rtpoll_free(pa_rtpoll
*p
) {
171 rtpoll_item_destroy(p
->items
);
174 pa_xfree(p
->pollfd2
);
179 static void reset_revents(pa_rtpoll_item
*i
) {
185 if (!(f
= pa_rtpoll_item_get_pollfd(i
, &n
)))
192 static void reset_all_revents(pa_rtpoll
*p
) {
197 for (i
= p
->items
; i
; i
= i
->next
) {
206 int pa_rtpoll_run(pa_rtpoll
*p
, pa_bool_t wait_op
) {
209 struct timeval timeout
;
212 pa_assert(!p
->running
);
215 pa_log("rtpoll_run");
219 p
->timer_elapsed
= FALSE
;
221 /* First, let's do some work */
222 for (i
= p
->items
; i
&& i
->priority
< PA_RTPOLL_NEVER
; i
= i
->next
) {
233 pa_log("rtpoll finish");
238 if ((k
= i
->work_cb(i
)) != 0) {
242 pa_log("rtpoll finish");
248 /* Now let's prepare for entering the sleep */
249 for (i
= p
->items
; i
&& i
->priority
< PA_RTPOLL_NEVER
; i
= i
->next
) {
258 if (p
->quit
|| (k
= i
->before_cb(i
)) != 0) {
260 /* Hmm, this one doesn't let us enter the poll, so rewind everything */
262 for (i
= i
->prev
; i
; i
= i
->prev
) {
276 pa_log("rtpoll finish");
282 if (p
->rebuild_needed
)
287 /* Calculate timeout */
288 if (wait_op
&& !p
->quit
&& p
->timer_enabled
) {
290 pa_rtclock_get(&now
);
292 if (pa_timeval_cmp(&p
->next_elapse
, &now
) > 0)
293 pa_timeval_add(&timeout
, pa_timeval_diff(&p
->next_elapse
, &now
));
298 pa_usec_t now
= pa_rtclock_now();
299 p
->awake
= now
- p
->timestamp
;
301 if (!wait_op
|| p
->quit
|| p
->timer_enabled
)
302 pa_log("poll timeout: %d ms ",(int) ((timeout
.tv_sec
*1000) + (timeout
.tv_usec
/ 1000)));
304 pa_log("poll timeout is ZERO");
308 /* OK, now let's sleep */
312 ts
.tv_sec
= timeout
.tv_sec
;
313 ts
.tv_nsec
= timeout
.tv_usec
* 1000;
314 r
= ppoll(p
->pollfd
, p
->n_pollfd_used
, (!wait_op
|| p
->quit
|| p
->timer_enabled
) ? &ts
: NULL
, NULL
);
317 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);
320 p
->timer_elapsed
= r
== 0;
324 pa_usec_t now
= pa_rtclock_now();
325 p
->slept
= now
- p
->timestamp
;
328 pa_log("Process time %llu ms; sleep time %llu ms",
329 (unsigned long long) (p
->awake
/ PA_USEC_PER_MSEC
),
330 (unsigned long long) (p
->slept
/ PA_USEC_PER_MSEC
));
335 if (errno
== EAGAIN
|| errno
== EINTR
)
338 pa_log_error("poll(): %s", pa_cstrerror(errno
));
340 reset_all_revents(p
);
343 /* Let's tell everyone that we left the sleep */
344 for (i
= p
->items
; i
&& i
->priority
< PA_RTPOLL_NEVER
; i
= i
->next
) {
359 if (p
->scan_for_dead
) {
362 p
->scan_for_dead
= FALSE
;
364 for (i
= p
->items
; i
; i
= n
) {
368 rtpoll_item_destroy(i
);
372 return r
< 0 ? r
: !p
->quit
;
375 void pa_rtpoll_set_timer_absolute(pa_rtpoll
*p
, pa_usec_t usec
) {
378 pa_timeval_store(&p
->next_elapse
, usec
);
379 p
->timer_enabled
= TRUE
;
382 void pa_rtpoll_set_timer_relative(pa_rtpoll
*p
, pa_usec_t usec
) {
385 /* Scheduling a timeout for more than an hour is very very suspicious */
386 pa_assert(usec
<= PA_USEC_PER_SEC
*60ULL*60ULL);
388 pa_rtclock_get(&p
->next_elapse
);
389 pa_timeval_add(&p
->next_elapse
, usec
);
390 p
->timer_enabled
= TRUE
;
393 void pa_rtpoll_set_timer_disabled(pa_rtpoll
*p
) {
396 memset(&p
->next_elapse
, 0, sizeof(p
->next_elapse
));
397 p
->timer_enabled
= FALSE
;
400 pa_rtpoll_item
*pa_rtpoll_item_new(pa_rtpoll
*p
, pa_rtpoll_priority_t prio
, unsigned n_fds
) {
401 pa_rtpoll_item
*i
, *j
, *l
= NULL
;
405 if (!(i
= pa_flist_pop(PA_STATIC_FLIST_GET(items
))))
406 i
= pa_xnew(pa_rtpoll_item
, 1);
419 for (j
= p
->items
; j
; j
= j
->next
) {
420 if (prio
<= j
->priority
)
426 PA_LLIST_INSERT_AFTER(pa_rtpoll_item
, p
->items
, j
? j
->prev
: l
, i
);
429 p
->rebuild_needed
= 1;
430 p
->n_pollfd_used
+= n_fds
;
436 void pa_rtpoll_item_free(pa_rtpoll_item
*i
) {
439 if (i
->rtpoll
->running
) {
441 i
->rtpoll
->scan_for_dead
= TRUE
;
445 rtpoll_item_destroy(i
);
448 struct pollfd
*pa_rtpoll_item_get_pollfd(pa_rtpoll_item
*i
, unsigned *n_fds
) {
452 if (i
->rtpoll
->rebuild_needed
)
453 rtpoll_rebuild(i
->rtpoll
);
456 *n_fds
= i
->n_pollfd
;
461 void pa_rtpoll_item_set_before_callback(pa_rtpoll_item
*i
, int (*before_cb
)(pa_rtpoll_item
*i
)) {
463 pa_assert(i
->priority
< PA_RTPOLL_NEVER
);
465 i
->before_cb
= before_cb
;
468 void pa_rtpoll_item_set_after_callback(pa_rtpoll_item
*i
, void (*after_cb
)(pa_rtpoll_item
*i
)) {
470 pa_assert(i
->priority
< PA_RTPOLL_NEVER
);
472 i
->after_cb
= after_cb
;
475 void pa_rtpoll_item_set_work_callback(pa_rtpoll_item
*i
, int (*work_cb
)(pa_rtpoll_item
*i
)) {
477 pa_assert(i
->priority
< PA_RTPOLL_NEVER
);
479 i
->work_cb
= work_cb
;
482 void pa_rtpoll_item_set_userdata(pa_rtpoll_item
*i
, void *userdata
) {
485 i
->userdata
= userdata
;
488 void* pa_rtpoll_item_get_userdata(pa_rtpoll_item
*i
) {
494 static int fdsem_before(pa_rtpoll_item
*i
) {
496 if (pa_fdsem_before_poll(i
->userdata
) < 0)
497 return 1; /* 1 means immediate restart of the loop */
502 static void fdsem_after(pa_rtpoll_item
*i
) {
505 pa_assert((i
->pollfd
[0].revents
& ~POLLIN
) == 0);
506 pa_fdsem_after_poll(i
->userdata
);
509 pa_rtpoll_item
*pa_rtpoll_item_new_fdsem(pa_rtpoll
*p
, pa_rtpoll_priority_t prio
, pa_fdsem
*f
) {
511 struct pollfd
*pollfd
;
516 i
= pa_rtpoll_item_new(p
, prio
, 1);
518 pollfd
= pa_rtpoll_item_get_pollfd(i
, NULL
);
520 pollfd
->fd
= pa_fdsem_get(f
);
521 pollfd
->events
= POLLIN
;
523 i
->before_cb
= fdsem_before
;
524 i
->after_cb
= fdsem_after
;
530 static int asyncmsgq_read_before(pa_rtpoll_item
*i
) {
533 if (pa_asyncmsgq_read_before_poll(i
->userdata
) < 0)
534 return 1; /* 1 means immediate restart of the loop */
539 static void asyncmsgq_read_after(pa_rtpoll_item
*i
) {
542 pa_assert((i
->pollfd
[0].revents
& ~POLLIN
) == 0);
543 pa_asyncmsgq_read_after_poll(i
->userdata
);
546 static int asyncmsgq_read_work(pa_rtpoll_item
*i
) {
547 pa_msgobject
*object
;
555 if (pa_asyncmsgq_get(i
->userdata
, &object
, &code
, &data
, &offset
, &chunk
, 0) == 0) {
558 if (!object
&& code
== PA_MESSAGE_SHUTDOWN
) {
559 pa_asyncmsgq_done(i
->userdata
, 0);
560 pa_rtpoll_quit(i
->rtpoll
);
564 ret
= pa_asyncmsgq_dispatch(object
, code
, data
, offset
, &chunk
);
565 pa_asyncmsgq_done(i
->userdata
, ret
);
572 pa_rtpoll_item
*pa_rtpoll_item_new_asyncmsgq_read(pa_rtpoll
*p
, pa_rtpoll_priority_t prio
, pa_asyncmsgq
*q
) {
574 struct pollfd
*pollfd
;
579 i
= pa_rtpoll_item_new(p
, prio
, 1);
581 pollfd
= pa_rtpoll_item_get_pollfd(i
, NULL
);
582 pollfd
->fd
= pa_asyncmsgq_read_fd(q
);
583 pollfd
->events
= POLLIN
;
585 i
->before_cb
= asyncmsgq_read_before
;
586 i
->after_cb
= asyncmsgq_read_after
;
587 i
->work_cb
= asyncmsgq_read_work
;
593 static int asyncmsgq_write_before(pa_rtpoll_item
*i
) {
596 pa_asyncmsgq_write_before_poll(i
->userdata
);
600 static void asyncmsgq_write_after(pa_rtpoll_item
*i
) {
603 pa_assert((i
->pollfd
[0].revents
& ~POLLIN
) == 0);
604 pa_asyncmsgq_write_after_poll(i
->userdata
);
607 pa_rtpoll_item
*pa_rtpoll_item_new_asyncmsgq_write(pa_rtpoll
*p
, pa_rtpoll_priority_t prio
, pa_asyncmsgq
*q
) {
609 struct pollfd
*pollfd
;
614 i
= pa_rtpoll_item_new(p
, prio
, 1);
616 pollfd
= pa_rtpoll_item_get_pollfd(i
, NULL
);
617 pollfd
->fd
= pa_asyncmsgq_write_fd(q
);
618 pollfd
->events
= POLLIN
;
620 i
->before_cb
= asyncmsgq_write_before
;
621 i
->after_cb
= asyncmsgq_write_after
;
628 void pa_rtpoll_quit(pa_rtpoll
*p
) {
634 pa_bool_t
pa_rtpoll_timer_elapsed(pa_rtpoll
*p
) {
637 return p
->timer_elapsed
;