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>
36 #include <pulsecore/poll.h>
39 #include <pulse/xmalloc.h>
40 #include <pulse/timeval.h>
42 #include <pulsecore/core-error.h>
43 #include <pulsecore/core-rtclock.h>
44 #include <pulsecore/macro.h>
45 #include <pulsecore/llist.h>
46 #include <pulsecore/flist.h>
47 #include <pulsecore/core-util.h>
48 #include <pulsecore/winsock.h>
49 #include <pulsecore/ratelimit.h>
53 /* #define DEBUG_TIMING */
56 struct pollfd
*pollfd
, *pollfd2
;
57 unsigned n_pollfd_alloc
, n_pollfd_used
;
59 struct timeval next_elapse
;
60 pa_bool_t timer_enabled
:1;
62 pa_bool_t scan_for_dead
:1;
64 pa_bool_t rebuild_needed
:1;
69 pa_usec_t slept
, awake
;
72 PA_LLIST_HEAD(pa_rtpoll_item
, items
);
75 struct pa_rtpoll_item
{
79 pa_rtpoll_priority_t priority
;
81 struct pollfd
*pollfd
;
84 int (*work_cb
)(pa_rtpoll_item
*i
);
85 int (*before_cb
)(pa_rtpoll_item
*i
);
86 void (*after_cb
)(pa_rtpoll_item
*i
);
89 PA_LLIST_FIELDS(pa_rtpoll_item
);
92 PA_STATIC_FLIST_DECLARE(items
, 0, pa_xfree
);
94 pa_rtpoll
*pa_rtpoll_new(void) {
97 p
= pa_xnew(pa_rtpoll
, 1);
99 p
->n_pollfd_alloc
= 32;
100 p
->pollfd
= pa_xnew(struct pollfd
, p
->n_pollfd_alloc
);
101 p
->pollfd2
= pa_xnew(struct pollfd
, p
->n_pollfd_alloc
);
102 p
->n_pollfd_used
= 0;
104 pa_zero(p
->next_elapse
);
105 p
->timer_enabled
= FALSE
;
108 p
->scan_for_dead
= FALSE
;
109 p
->rebuild_needed
= FALSE
;
112 PA_LLIST_HEAD_INIT(pa_rtpoll_item
, p
->items
);
115 p
->timestamp
= pa_rtclock_now();
116 p
->slept
= p
->awake
= 0;
122 static void rtpoll_rebuild(pa_rtpoll
*p
) {
124 struct pollfd
*e
, *t
;
130 p
->rebuild_needed
= FALSE
;
132 if (p
->n_pollfd_used
> p
->n_pollfd_alloc
) {
133 /* Hmm, we have to allocate some more space */
134 p
->n_pollfd_alloc
= p
->n_pollfd_used
* 2;
135 p
->pollfd2
= pa_xrealloc(p
->pollfd2
, p
->n_pollfd_alloc
* sizeof(struct pollfd
));
141 for (i
= p
->items
; i
; i
= i
->next
) {
143 if (i
->n_pollfd
> 0) {
144 size_t l
= i
->n_pollfd
* sizeof(struct pollfd
);
147 memcpy(e
, i
->pollfd
, l
);
158 pa_assert((unsigned) (e
- p
->pollfd2
) == p
->n_pollfd_used
);
160 p
->pollfd
= p
->pollfd2
;
164 p
->pollfd2
= pa_xrealloc(p
->pollfd2
, p
->n_pollfd_alloc
* sizeof(struct pollfd
));
167 static void rtpoll_item_destroy(pa_rtpoll_item
*i
) {
174 PA_LLIST_REMOVE(pa_rtpoll_item
, p
->items
, i
);
176 p
->n_pollfd_used
-= i
->n_pollfd
;
178 if (pa_flist_push(PA_STATIC_FLIST_GET(items
), i
) < 0)
181 p
->rebuild_needed
= TRUE
;
184 void pa_rtpoll_free(pa_rtpoll
*p
) {
188 rtpoll_item_destroy(p
->items
);
191 pa_xfree(p
->pollfd2
);
196 static void reset_revents(pa_rtpoll_item
*i
) {
202 if (!(f
= pa_rtpoll_item_get_pollfd(i
, &n
)))
209 static void reset_all_revents(pa_rtpoll
*p
) {
214 for (i
= p
->items
; i
; i
= i
->next
) {
223 int pa_rtpoll_run(pa_rtpoll
*p
, pa_bool_t wait_op
) {
226 struct timeval timeout
;
229 pa_assert(!p
->running
);
233 /* First, let's do some work */
234 for (i
= p
->items
; i
&& i
->priority
< PA_RTPOLL_NEVER
; i
= i
->next
) {
246 if ((k
= i
->work_cb(i
)) != 0) {
254 /* Now let's prepare for entering the sleep */
255 for (i
= p
->items
; i
&& i
->priority
< PA_RTPOLL_NEVER
; i
= i
->next
) {
264 if (p
->quit
|| (k
= i
->before_cb(i
)) != 0) {
266 /* Hmm, this one doesn't let us enter the poll, so rewind everything */
268 for (i
= i
->prev
; i
; i
= i
->prev
) {
286 if (p
->rebuild_needed
)
289 memset(&timeout
, 0, sizeof(timeout
));
291 /* Calculate timeout */
292 if (wait_op
&& !p
->quit
&& p
->timer_enabled
) {
294 pa_rtclock_get(&now
);
296 if (pa_timeval_cmp(&p
->next_elapse
, &now
) > 0)
297 pa_timeval_add(&timeout
, pa_timeval_diff(&p
->next_elapse
, &now
));
302 pa_usec_t now
= pa_rtclock_now();
303 p
->awake
= now
- p
->timestamp
;
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
= poll(p
->pollfd
, p
->n_pollfd_used
, (!wait_op
|| p
->quit
|| p
->timer_enabled
) ? (int) ((timeout
.tv_sec
*1000) + (timeout
.tv_usec
/ 1000)) : -1);
322 pa_usec_t now
= pa_rtclock_now();
323 p
->slept
= now
- p
->timestamp
;
326 pa_log("Process time %llu ms; sleep time %llu ms",
327 (unsigned long long) (p
->awake
/ PA_USEC_PER_MSEC
),
328 (unsigned long long) (p
->slept
/ PA_USEC_PER_MSEC
));
333 if (errno
== EAGAIN
|| errno
== EINTR
)
336 pa_log_error("poll(): %s", pa_cstrerror(errno
));
338 reset_all_revents(p
);
341 /* Let's tell everyone that we left the sleep */
342 for (i
= p
->items
; i
&& i
->priority
< PA_RTPOLL_NEVER
; i
= i
->next
) {
357 if (p
->scan_for_dead
) {
360 p
->scan_for_dead
= FALSE
;
362 for (i
= p
->items
; i
; i
= n
) {
366 rtpoll_item_destroy(i
);
370 return r
< 0 ? r
: !p
->quit
;
373 void pa_rtpoll_set_timer_absolute(pa_rtpoll
*p
, pa_usec_t usec
) {
376 pa_timeval_store(&p
->next_elapse
, usec
);
377 p
->timer_enabled
= TRUE
;
380 void pa_rtpoll_set_timer_relative(pa_rtpoll
*p
, pa_usec_t usec
) {
383 /* Scheduling a timeout for more than an hour is very very suspicious */
384 pa_assert(usec
<= PA_USEC_PER_SEC
*60ULL*60ULL);
386 pa_rtclock_get(&p
->next_elapse
);
387 pa_timeval_add(&p
->next_elapse
, usec
);
388 p
->timer_enabled
= TRUE
;
391 void pa_rtpoll_set_timer_disabled(pa_rtpoll
*p
) {
394 memset(&p
->next_elapse
, 0, sizeof(p
->next_elapse
));
395 p
->timer_enabled
= FALSE
;
398 pa_rtpoll_item
*pa_rtpoll_item_new(pa_rtpoll
*p
, pa_rtpoll_priority_t prio
, unsigned n_fds
) {
399 pa_rtpoll_item
*i
, *j
, *l
= NULL
;
403 if (!(i
= pa_flist_pop(PA_STATIC_FLIST_GET(items
))))
404 i
= pa_xnew(pa_rtpoll_item
, 1);
417 for (j
= p
->items
; j
; j
= j
->next
) {
418 if (prio
<= j
->priority
)
424 PA_LLIST_INSERT_AFTER(pa_rtpoll_item
, p
->items
, j
? j
->prev
: l
, i
);
427 p
->rebuild_needed
= 1;
428 p
->n_pollfd_used
+= n_fds
;
434 void pa_rtpoll_item_free(pa_rtpoll_item
*i
) {
437 if (i
->rtpoll
->running
) {
439 i
->rtpoll
->scan_for_dead
= TRUE
;
443 rtpoll_item_destroy(i
);
446 struct pollfd
*pa_rtpoll_item_get_pollfd(pa_rtpoll_item
*i
, unsigned *n_fds
) {
450 if (i
->rtpoll
->rebuild_needed
)
451 rtpoll_rebuild(i
->rtpoll
);
454 *n_fds
= i
->n_pollfd
;
459 void pa_rtpoll_item_set_before_callback(pa_rtpoll_item
*i
, int (*before_cb
)(pa_rtpoll_item
*i
)) {
461 pa_assert(i
->priority
< PA_RTPOLL_NEVER
);
463 i
->before_cb
= before_cb
;
466 void pa_rtpoll_item_set_after_callback(pa_rtpoll_item
*i
, void (*after_cb
)(pa_rtpoll_item
*i
)) {
468 pa_assert(i
->priority
< PA_RTPOLL_NEVER
);
470 i
->after_cb
= after_cb
;
473 void pa_rtpoll_item_set_work_callback(pa_rtpoll_item
*i
, int (*work_cb
)(pa_rtpoll_item
*i
)) {
475 pa_assert(i
->priority
< PA_RTPOLL_NEVER
);
477 i
->work_cb
= work_cb
;
480 void pa_rtpoll_item_set_userdata(pa_rtpoll_item
*i
, void *userdata
) {
483 i
->userdata
= userdata
;
486 void* pa_rtpoll_item_get_userdata(pa_rtpoll_item
*i
) {
492 static int fdsem_before(pa_rtpoll_item
*i
) {
494 if (pa_fdsem_before_poll(i
->userdata
) < 0)
495 return 1; /* 1 means immediate restart of the loop */
500 static void fdsem_after(pa_rtpoll_item
*i
) {
503 pa_assert((i
->pollfd
[0].revents
& ~POLLIN
) == 0);
504 pa_fdsem_after_poll(i
->userdata
);
507 pa_rtpoll_item
*pa_rtpoll_item_new_fdsem(pa_rtpoll
*p
, pa_rtpoll_priority_t prio
, pa_fdsem
*f
) {
509 struct pollfd
*pollfd
;
514 i
= pa_rtpoll_item_new(p
, prio
, 1);
516 pollfd
= pa_rtpoll_item_get_pollfd(i
, NULL
);
518 pollfd
->fd
= pa_fdsem_get(f
);
519 pollfd
->events
= POLLIN
;
521 i
->before_cb
= fdsem_before
;
522 i
->after_cb
= fdsem_after
;
528 static int asyncmsgq_read_before(pa_rtpoll_item
*i
) {
531 if (pa_asyncmsgq_read_before_poll(i
->userdata
) < 0)
532 return 1; /* 1 means immediate restart of the loop */
537 static void asyncmsgq_read_after(pa_rtpoll_item
*i
) {
540 pa_assert((i
->pollfd
[0].revents
& ~POLLIN
) == 0);
541 pa_asyncmsgq_read_after_poll(i
->userdata
);
544 static int asyncmsgq_read_work(pa_rtpoll_item
*i
) {
545 pa_msgobject
*object
;
553 if (pa_asyncmsgq_get(i
->userdata
, &object
, &code
, &data
, &offset
, &chunk
, 0) == 0) {
556 if (!object
&& code
== PA_MESSAGE_SHUTDOWN
) {
557 pa_asyncmsgq_done(i
->userdata
, 0);
558 pa_rtpoll_quit(i
->rtpoll
);
562 ret
= pa_asyncmsgq_dispatch(object
, code
, data
, offset
, &chunk
);
563 pa_asyncmsgq_done(i
->userdata
, ret
);
570 pa_rtpoll_item
*pa_rtpoll_item_new_asyncmsgq_read(pa_rtpoll
*p
, pa_rtpoll_priority_t prio
, pa_asyncmsgq
*q
) {
572 struct pollfd
*pollfd
;
577 i
= pa_rtpoll_item_new(p
, prio
, 1);
579 pollfd
= pa_rtpoll_item_get_pollfd(i
, NULL
);
580 pollfd
->fd
= pa_asyncmsgq_read_fd(q
);
581 pollfd
->events
= POLLIN
;
583 i
->before_cb
= asyncmsgq_read_before
;
584 i
->after_cb
= asyncmsgq_read_after
;
585 i
->work_cb
= asyncmsgq_read_work
;
591 static int asyncmsgq_write_before(pa_rtpoll_item
*i
) {
594 pa_asyncmsgq_write_before_poll(i
->userdata
);
598 static void asyncmsgq_write_after(pa_rtpoll_item
*i
) {
601 pa_assert((i
->pollfd
[0].revents
& ~POLLIN
) == 0);
602 pa_asyncmsgq_write_after_poll(i
->userdata
);
605 pa_rtpoll_item
*pa_rtpoll_item_new_asyncmsgq_write(pa_rtpoll
*p
, pa_rtpoll_priority_t prio
, pa_asyncmsgq
*q
) {
607 struct pollfd
*pollfd
;
612 i
= pa_rtpoll_item_new(p
, prio
, 1);
614 pollfd
= pa_rtpoll_item_get_pollfd(i
, NULL
);
615 pollfd
->fd
= pa_asyncmsgq_write_fd(q
);
616 pollfd
->events
= POLLIN
;
618 i
->before_cb
= asyncmsgq_write_before
;
619 i
->after_cb
= asyncmsgq_write_after
;
626 void pa_rtpoll_quit(pa_rtpoll
*p
) {