]> code.delx.au - pulseaudio/blob - src/pulsecore/rtpoll.c
add new realtime event loop abstraction which precise time keeping by using hrtimers...
[pulseaudio] / src / pulsecore / rtpoll.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
8
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.
13
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.
18
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
22 USA.
23 ***/
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <sys/utsname.h>
30 #include <sys/types.h>
31 #include <stdio.h>
32 #include <signal.h>
33 #include <string.h>
34 #include <errno.h>
35
36 #include <pulse/xmalloc.h>
37
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>
44
45 #include "rtpoll.h"
46
47 struct pa_rtpoll {
48
49 struct pollfd *pollfd, *pollfd2;
50 unsigned n_pollfd_alloc, n_pollfd_used;
51
52 pa_usec_t interval;
53
54 int scan_for_dead;
55 int running, installed, rebuild_needed;
56
57 #ifdef HAVE_PPOLL
58 int rtsig;
59 sigset_t sigset_unblocked;
60 struct timespec interval_timespec;
61 timer_t timer;
62 #ifdef __linux__
63 int dont_use_ppoll;
64 #endif
65 #endif
66
67 PA_LLIST_HEAD(pa_rtpoll_item, items);
68 };
69
70 struct pa_rtpoll_item {
71 pa_rtpoll *rtpoll;
72 int dead;
73
74 struct pollfd *pollfd;
75 unsigned n_pollfd;
76
77 int (*before_cb)(pa_rtpoll_item *i);
78 void (*after_cb)(pa_rtpoll_item *i);
79 void *userdata;
80
81 PA_LLIST_FIELDS(pa_rtpoll_item);
82 };
83
84 PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree);
85
86 static void signal_handler_noop(int s) { }
87
88 pa_rtpoll *pa_rtpoll_new(void) {
89 pa_rtpoll *p;
90
91 p = pa_xnew(pa_rtpoll, 1);
92
93 #ifdef HAVE_PPOLL
94
95 #ifdef __linux__
96 /* ppoll is broken on Linux < 2.6.16 */
97
98 p->dont_use_ppoll = 0;
99
100 {
101 struct utsname u;
102 unsigned major, minor, micro;
103
104 pa_assert_se(uname(&u) == 0);
105
106 if (sscanf(u.release, "%u.%u.%u", &major, &minor, &micro) != 3 ||
107 (major < 2) ||
108 (major == 2 && minor < 6) ||
109 (major == 2 && minor == 6 && micro < 16))
110
111 p->dont_use_ppoll = 1;
112 }
113
114 #endif
115
116 p->rtsig = -1;
117 sigemptyset(&p->sigset_unblocked);
118 memset(&p->interval_timespec, 0, sizeof(p->interval_timespec));
119 p->timer = (timer_t) -1;
120
121 #endif
122
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;
127
128 p->interval = 0;
129
130 p->running = 0;
131 p->installed = 0;
132 p->scan_for_dead = 0;
133 p->rebuild_needed = 0;
134
135 PA_LLIST_HEAD_INIT(pa_rtpoll_item, p->items);
136
137 return p;
138 }
139
140 void pa_rtpoll_install(pa_rtpoll *p) {
141 pa_assert(p);
142 pa_assert(!p->installed);
143
144 p->installed = 1;
145
146 #ifdef HAVE_PPOLL
147 if (p->dont_use_ppoll)
148 return;
149
150 if ((p->rtsig = pa_rtsig_get_for_thread()) < 0) {
151 pa_log_warn("Failed to reserve POSIX realtime signal.");
152 return;
153 }
154
155 pa_log_debug("Acquired POSIX realtime signal SIGRTMIN+%i", p->rtsig - SIGRTMIN);
156
157 {
158 sigset_t ss;
159 struct sigaction sa;
160
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);
165
166 memset(&sa, 0, sizeof(sa));
167 sa.sa_handler = signal_handler_noop;
168 pa_assert_se(sigemptyset(&sa.sa_mask) == 0);
169
170 pa_assert_se(sigaction(p->rtsig, &sa, NULL) == 0);
171
172 /* We never reset the signal handler. Why should we? */
173 }
174
175 #endif
176 }
177
178 static void rtpoll_rebuild(pa_rtpoll *p) {
179
180 struct pollfd *e, *t;
181 pa_rtpoll_item *i;
182 int ra = 0;
183
184 pa_assert(p);
185
186 p->rebuild_needed = 0;
187
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));
192 ra = 1;
193 }
194
195 e = p->pollfd2;
196
197 for (i = p->items; i; i = i->next) {
198
199 if (i->n_pollfd > 0) {
200 size_t l = i->n_pollfd * sizeof(struct pollfd);
201
202 if (i->pollfd)
203 memcpy(e, i->pollfd, l);
204 else
205 memset(e, 0, l);
206
207 i->pollfd = e;
208 } else
209 i->pollfd = NULL;
210
211 e += i->n_pollfd;
212 }
213
214 pa_assert((unsigned) (e - p->pollfd2) == p->n_pollfd_used);
215 t = p->pollfd;
216 p->pollfd = p->pollfd2;
217 p->pollfd2 = t;
218
219 if (ra)
220 p->pollfd2 = pa_xrealloc(p->pollfd2, p->n_pollfd_alloc * sizeof(struct pollfd));
221
222 }
223
224 static void rtpoll_item_destroy(pa_rtpoll_item *i) {
225 pa_rtpoll *p;
226
227 pa_assert(i);
228
229 p = i->rtpoll;
230
231 PA_LLIST_REMOVE(pa_rtpoll_item, p->items, i);
232
233 p->n_pollfd_used -= i->n_pollfd;
234
235 if (pa_flist_push(PA_STATIC_FLIST_GET(items), i) < 0)
236 pa_xfree(i);
237
238 p->rebuild_needed = 1;
239 }
240
241 void pa_rtpoll_free(pa_rtpoll *p) {
242 pa_assert(p);
243
244 pa_assert(!p->items);
245 pa_xfree(p->pollfd);
246 pa_xfree(p->pollfd2);
247
248 #ifdef HAVE_PPOLL
249 if (p->timer != (timer_t) -1)
250 timer_delete(p->timer);
251 #endif
252
253 pa_xfree(p);
254 }
255
256 int pa_rtpoll_run(pa_rtpoll *p) {
257 pa_rtpoll_item *i;
258 int r = 0;
259
260 pa_assert(p);
261 pa_assert(!p->running);
262 pa_assert(p->installed);
263
264 p->running = 1;
265
266 for (i = p->items; i; i = i->next) {
267
268 if (i->dead)
269 continue;
270
271 if (!i->before_cb)
272 continue;
273
274 if (i->before_cb(i) < 0) {
275
276 /* Hmm, this one doesn't let us enter the poll, so rewind everything */
277
278 for (i = i->prev; i; i = i->prev) {
279
280 if (i->dead)
281 continue;
282
283 if (!i->after_cb)
284 continue;
285
286 i->after_cb(i);
287 }
288
289 goto finish;
290 }
291 }
292
293 if (p->rebuild_needed)
294 rtpoll_rebuild(p);
295
296 /* OK, now let's sleep */
297 #ifdef HAVE_PPOLL
298
299 #ifdef __linux__
300 if (!p->dont_use_ppoll)
301 #endif
302 r = ppoll(p->pollfd, p->n_pollfd_used, p->interval > 0 ? &p->interval_timespec : NULL, p->rtsig < 0 ? NULL : &p->sigset_unblocked);
303 #ifdef __linux__
304 else
305 #endif
306
307 #else
308 r = poll(p->pollfd, p->n_pollfd_used, p->interval > 0 ? p->interval / 1000 : -1);
309 #endif
310
311 if (r < 0 && (errno == EAGAIN || errno == EINTR))
312 r = 0;
313
314 for (i = p->items; i; i = i->next) {
315
316 if (i->dead)
317 continue;
318
319 if (!i->after_cb)
320 continue;
321
322 i->after_cb(i);
323 }
324
325 finish:
326
327 p->running = 0;
328
329 if (p->scan_for_dead) {
330 pa_rtpoll_item *n;
331
332 p->scan_for_dead = 0;
333
334 for (i = p->items; i; i = n) {
335 n = i->next;
336
337 if (i->dead)
338 rtpoll_item_destroy(i);
339 }
340 }
341
342 return r;
343 }
344
345 void pa_rtpoll_set_itimer(pa_rtpoll *p, pa_usec_t usec) {
346 pa_assert(p);
347
348 p->interval = usec;
349
350 #ifdef HAVE_PPOLL
351 pa_timespec_store(&p->interval_timespec, usec);
352
353 #ifdef __linux__
354 if (!p->dont_use_ppoll) {
355 #endif
356
357 if (p->timer == (timer_t) -1) {
358 struct sigevent se;
359
360 memset(&se, 0, sizeof(se));
361 se.sigev_notify = SIGEV_SIGNAL;
362 se.sigev_signo = p->rtsig;
363
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;
368 }
369 }
370
371 if (p->timer != (timer_t) -1) {
372 struct itimerspec its;
373
374 memset(&its, 0, sizeof(its));
375 pa_timespec_store(&its.it_value, usec);
376 pa_timespec_store(&its.it_interval, usec);
377
378 assert(timer_settime(p->timer, 0, &its, NULL) == 0);
379 }
380
381 #ifdef __linux__
382 }
383 #endif
384
385 #endif
386 }
387
388 pa_rtpoll_item *pa_rtpoll_item_new(pa_rtpoll *p, unsigned n_fds) {
389 pa_rtpoll_item *i;
390
391 pa_assert(p);
392 pa_assert(n_fds > 0);
393
394 if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items))))
395 i = pa_xnew(pa_rtpoll_item, 1);
396
397 i->rtpoll = p;
398 i->dead = 0;
399 i->n_pollfd = n_fds;
400 i->pollfd = NULL;
401
402 i->userdata = NULL;
403 i->before_cb = NULL;
404 i->after_cb = NULL;
405
406 PA_LLIST_PREPEND(pa_rtpoll_item, p->items, i);
407
408 p->rebuild_needed = 1;
409 p->n_pollfd_used += n_fds;
410
411 return i;
412 }
413
414 void pa_rtpoll_item_free(pa_rtpoll_item *i) {
415 pa_assert(i);
416
417 if (i->rtpoll->running) {
418 i->dead = 1;
419 i->rtpoll->scan_for_dead = 1;
420 return;
421 }
422
423 rtpoll_item_destroy(i);
424 }
425
426 struct pollfd *pa_rtpoll_item_get_pollfd(pa_rtpoll_item *i, unsigned *n_fds) {
427 pa_assert(i);
428
429 if (i->rtpoll->rebuild_needed)
430 rtpoll_rebuild(i->rtpoll);
431
432 if (n_fds)
433 *n_fds = i->n_pollfd;
434
435 return i->pollfd;
436 }
437
438 void pa_rtpoll_item_set_before_callback(pa_rtpoll_item *i, int (*before_cb)(pa_rtpoll_item *i)) {
439 pa_assert(i);
440
441 i->before_cb = before_cb;
442 }
443
444 void pa_rtpoll_item_set_after_callback(pa_rtpoll_item *i, void (*after_cb)(pa_rtpoll_item *i)) {
445 pa_assert(i);
446
447 i->after_cb = after_cb;
448 }
449
450 void pa_rtpoll_item_set_userdata(pa_rtpoll_item *i, void *userdata) {
451 pa_assert(i);
452
453 i->userdata = userdata;
454 }