4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
9 PulseAudio is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as
11 published by the Free Software Foundation; either version 2.1 of the
12 License, or (at your option) any later version.
14 PulseAudio is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public
20 License along with PulseAudio; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
29 #include <sys/utsname.h>
30 #include <sys/types.h>
36 #include <pulse/xmalloc.h>
38 #include <pulsecore/core-error.h>
39 #include <pulsecore/rtclock.h>
40 #include <pulsecore/macro.h>
41 #include <pulsecore/llist.h>
42 #include <pulsecore/rtsig.h>
43 #include <pulsecore/flist.h>
49 struct pollfd
*pollfd
, *pollfd2
;
50 unsigned n_pollfd_alloc
, n_pollfd_used
;
55 int running
, installed
, rebuild_needed
;
59 sigset_t sigset_unblocked
;
60 struct timespec interval_timespec
;
67 PA_LLIST_HEAD(pa_rtpoll_item
, items
);
70 struct pa_rtpoll_item
{
74 struct pollfd
*pollfd
;
77 int (*before_cb
)(pa_rtpoll_item
*i
);
78 void (*after_cb
)(pa_rtpoll_item
*i
);
81 PA_LLIST_FIELDS(pa_rtpoll_item
);
84 PA_STATIC_FLIST_DECLARE(items
, 0, pa_xfree
);
86 static void signal_handler_noop(int s
) { }
88 pa_rtpoll
*pa_rtpoll_new(void) {
91 p
= pa_xnew(pa_rtpoll
, 1);
96 /* ppoll is broken on Linux < 2.6.16 */
98 p
->dont_use_ppoll
= 0;
102 unsigned major
, minor
, micro
;
104 pa_assert_se(uname(&u
) == 0);
106 if (sscanf(u
.release
, "%u.%u.%u", &major
, &minor
, µ
) != 3 ||
108 (major
== 2 && minor
< 6) ||
109 (major
== 2 && minor
== 6 && micro
< 16))
111 p
->dont_use_ppoll
= 1;
117 sigemptyset(&p
->sigset_unblocked
);
118 memset(&p
->interval_timespec
, 0, sizeof(p
->interval_timespec
));
119 p
->timer
= (timer_t
) -1;
123 p
->n_pollfd_alloc
= 32;
124 p
->pollfd
= pa_xnew(struct pollfd
, p
->n_pollfd_alloc
);
125 p
->pollfd2
= pa_xnew(struct pollfd
, p
->n_pollfd_alloc
);
126 p
->n_pollfd_used
= 0;
132 p
->scan_for_dead
= 0;
133 p
->rebuild_needed
= 0;
135 PA_LLIST_HEAD_INIT(pa_rtpoll_item
, p
->items
);
140 void pa_rtpoll_install(pa_rtpoll
*p
) {
142 pa_assert(!p
->installed
);
147 if (p
->dont_use_ppoll
)
150 if ((p
->rtsig
= pa_rtsig_get_for_thread()) < 0) {
151 pa_log_warn("Failed to reserve POSIX realtime signal.");
155 pa_log_debug("Acquired POSIX realtime signal SIGRTMIN+%i", p
->rtsig
- SIGRTMIN
);
161 pa_assert_se(sigemptyset(&ss
) == 0);
162 pa_assert_se(sigaddset(&ss
, p
->rtsig
) == 0);
163 pa_assert_se(pthread_sigmask(SIG_BLOCK
, &ss
, &p
->sigset_unblocked
) == 0);
164 pa_assert_se(sigdelset(&p
->sigset_unblocked
, p
->rtsig
) == 0);
166 memset(&sa
, 0, sizeof(sa
));
167 sa
.sa_handler
= signal_handler_noop
;
168 pa_assert_se(sigemptyset(&sa
.sa_mask
) == 0);
170 pa_assert_se(sigaction(p
->rtsig
, &sa
, NULL
) == 0);
172 /* We never reset the signal handler. Why should we? */
178 static void rtpoll_rebuild(pa_rtpoll
*p
) {
180 struct pollfd
*e
, *t
;
186 p
->rebuild_needed
= 0;
188 if (p
->n_pollfd_used
> p
->n_pollfd_alloc
) {
189 /* Hmm, we have to allocate some more space */
190 p
->n_pollfd_alloc
= p
->n_pollfd_used
* 2;
191 p
->pollfd2
= pa_xrealloc(p
->pollfd2
, p
->n_pollfd_alloc
* sizeof(struct pollfd
));
197 for (i
= p
->items
; i
; i
= i
->next
) {
199 if (i
->n_pollfd
> 0) {
200 size_t l
= i
->n_pollfd
* sizeof(struct pollfd
);
203 memcpy(e
, i
->pollfd
, l
);
214 pa_assert((unsigned) (e
- p
->pollfd2
) == p
->n_pollfd_used
);
216 p
->pollfd
= p
->pollfd2
;
220 p
->pollfd2
= pa_xrealloc(p
->pollfd2
, p
->n_pollfd_alloc
* sizeof(struct pollfd
));
224 static void rtpoll_item_destroy(pa_rtpoll_item
*i
) {
231 PA_LLIST_REMOVE(pa_rtpoll_item
, p
->items
, i
);
233 p
->n_pollfd_used
-= i
->n_pollfd
;
235 if (pa_flist_push(PA_STATIC_FLIST_GET(items
), i
) < 0)
238 p
->rebuild_needed
= 1;
241 void pa_rtpoll_free(pa_rtpoll
*p
) {
244 pa_assert(!p
->items
);
246 pa_xfree(p
->pollfd2
);
249 if (p
->timer
!= (timer_t
) -1)
250 timer_delete(p
->timer
);
256 int pa_rtpoll_run(pa_rtpoll
*p
) {
261 pa_assert(!p
->running
);
262 pa_assert(p
->installed
);
266 for (i
= p
->items
; i
; i
= i
->next
) {
274 if (i
->before_cb(i
) < 0) {
276 /* Hmm, this one doesn't let us enter the poll, so rewind everything */
278 for (i
= i
->prev
; i
; i
= i
->prev
) {
293 if (p
->rebuild_needed
)
296 /* OK, now let's sleep */
300 if (!p
->dont_use_ppoll
)
302 r
= ppoll(p
->pollfd
, p
->n_pollfd_used
, p
->interval
> 0 ? &p
->interval_timespec
: NULL
, p
->rtsig
< 0 ? NULL
: &p
->sigset_unblocked
);
308 r
= poll(p
->pollfd
, p
->n_pollfd_used
, p
->interval
> 0 ? p
->interval
/ 1000 : -1);
311 if (r
< 0 && (errno
== EAGAIN
|| errno
== EINTR
))
314 for (i
= p
->items
; i
; i
= i
->next
) {
329 if (p
->scan_for_dead
) {
332 p
->scan_for_dead
= 0;
334 for (i
= p
->items
; i
; i
= n
) {
338 rtpoll_item_destroy(i
);
345 void pa_rtpoll_set_itimer(pa_rtpoll
*p
, pa_usec_t usec
) {
351 pa_timespec_store(&p
->interval_timespec
, usec
);
354 if (!p
->dont_use_ppoll
) {
357 if (p
->timer
== (timer_t
) -1) {
360 memset(&se
, 0, sizeof(se
));
361 se
.sigev_notify
= SIGEV_SIGNAL
;
362 se
.sigev_signo
= p
->rtsig
;
364 if (timer_create(CLOCK_MONOTONIC
, &se
, &p
->timer
) < 0)
365 if (timer_create(CLOCK_REALTIME
, &se
, &p
->timer
) < 0) {
366 pa_log_warn("Failed to allocate POSIX timer: %s", pa_cstrerror(errno
));
367 p
->timer
= (timer_t
) -1;
371 if (p
->timer
!= (timer_t
) -1) {
372 struct itimerspec its
;
374 memset(&its
, 0, sizeof(its
));
375 pa_timespec_store(&its
.it_value
, usec
);
376 pa_timespec_store(&its
.it_interval
, usec
);
378 assert(timer_settime(p
->timer
, 0, &its
, NULL
) == 0);
388 pa_rtpoll_item
*pa_rtpoll_item_new(pa_rtpoll
*p
, unsigned n_fds
) {
392 pa_assert(n_fds
> 0);
394 if (!(i
= pa_flist_pop(PA_STATIC_FLIST_GET(items
))))
395 i
= pa_xnew(pa_rtpoll_item
, 1);
406 PA_LLIST_PREPEND(pa_rtpoll_item
, p
->items
, i
);
408 p
->rebuild_needed
= 1;
409 p
->n_pollfd_used
+= n_fds
;
414 void pa_rtpoll_item_free(pa_rtpoll_item
*i
) {
417 if (i
->rtpoll
->running
) {
419 i
->rtpoll
->scan_for_dead
= 1;
423 rtpoll_item_destroy(i
);
426 struct pollfd
*pa_rtpoll_item_get_pollfd(pa_rtpoll_item
*i
, unsigned *n_fds
) {
429 if (i
->rtpoll
->rebuild_needed
)
430 rtpoll_rebuild(i
->rtpoll
);
433 *n_fds
= i
->n_pollfd
;
438 void pa_rtpoll_item_set_before_callback(pa_rtpoll_item
*i
, int (*before_cb
)(pa_rtpoll_item
*i
)) {
441 i
->before_cb
= before_cb
;
444 void pa_rtpoll_item_set_after_callback(pa_rtpoll_item
*i
, void (*after_cb
)(pa_rtpoll_item
*i
)) {
447 i
->after_cb
= after_cb
;
450 void pa_rtpoll_item_set_userdata(pa_rtpoll_item
*i
, void *userdata
) {
453 i
->userdata
= userdata
;