1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
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.
11
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.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <sys/types.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <errno.h>
29
30 #include <pulse/xmalloc.h>
31 #include <pulse/timeval.h>
32
33 #include <pulsecore/poll.h>
34 #include <pulsecore/core-error.h>
35 #include <pulsecore/core-rtclock.h>
36 #include <pulsecore/macro.h>
37 #include <pulsecore/llist.h>
38 #include <pulsecore/flist.h>
39 #include <pulsecore/core-util.h>
40 #include <pulsecore/ratelimit.h>
41 #include <pulse/rtclock.h>
42
43 #include "log/audio_log.h"
44
45 #include "rtpoll.h"
46 #include "time.h"
47
48 /* #define DEBUG_TIMING */
49
50 struct pa_rtpoll {
51 struct pollfd *pollfd, *pollfd2;
52 unsigned n_pollfd_alloc, n_pollfd_used;
53
54 struct timeval next_elapse;
55 bool timer_enabled:1;
56
57 bool scan_for_dead:1;
58 bool running:1;
59 bool rebuild_needed:1;
60 bool quit:1;
61 bool timer_elapsed:1;
62
63 #ifdef DEBUG_TIMING
64 pa_usec_t timestamp;
65 pa_usec_t slept, awake;
66 #endif
67
68 PA_LLIST_HEAD(pa_rtpoll_item, items);
69 };
70
71 struct pa_rtpoll_item {
72 pa_rtpoll *rtpoll;
73 bool dead;
74
75 pa_rtpoll_priority_t priority;
76
77 struct pollfd *pollfd;
78 unsigned n_pollfd;
79
80 int (*work_cb)(pa_rtpoll_item *i);
81 int (*before_cb)(pa_rtpoll_item *i);
82 void (*after_cb)(pa_rtpoll_item *i);
83 void *work_userdata;
84 void *before_userdata;
85 void *after_userdata;
86
87 PA_LLIST_FIELDS(pa_rtpoll_item);
88 };
89
90 PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree);
91
pa_rtpoll_new(void)92 pa_rtpoll *pa_rtpoll_new(void) {
93 pa_rtpoll *p;
94
95 p = pa_xnew0(pa_rtpoll, 1);
96
97 p->n_pollfd_alloc = 32;
98 p->pollfd = pa_xnew(struct pollfd, p->n_pollfd_alloc);
99 p->pollfd2 = pa_xnew(struct pollfd, p->n_pollfd_alloc);
100
101 #ifdef DEBUG_TIMING
102 p->timestamp = pa_rtclock_now();
103 #endif
104
105 return p;
106 }
107
rtpoll_rebuild(pa_rtpoll * p)108 static void rtpoll_rebuild(pa_rtpoll *p) {
109
110 struct pollfd *e, *t;
111 pa_rtpoll_item *i;
112 int ra = 0;
113
114 pa_assert(p);
115
116 p->rebuild_needed = false;
117
118 if (p->n_pollfd_used > p->n_pollfd_alloc) {
119 /* Hmm, we have to allocate some more space */
120 p->n_pollfd_alloc = p->n_pollfd_used * 2;
121 p->pollfd2 = pa_xrealloc(p->pollfd2, p->n_pollfd_alloc * sizeof(struct pollfd));
122 ra = 1;
123 }
124
125 e = p->pollfd2;
126
127 for (i = p->items; i; i = i->next) {
128
129 if (i->n_pollfd > 0) {
130 size_t l = i->n_pollfd * sizeof(struct pollfd);
131
132 if (i->pollfd)
133 memcpy(e, i->pollfd, l);
134 else
135 memset(e, 0, l);
136
137 i->pollfd = e;
138 } else
139 i->pollfd = NULL;
140
141 e += i->n_pollfd;
142 }
143
144 pa_assert((unsigned) (e - p->pollfd2) == p->n_pollfd_used);
145 t = p->pollfd;
146 p->pollfd = p->pollfd2;
147 p->pollfd2 = t;
148
149 if (ra)
150 p->pollfd2 = pa_xrealloc(p->pollfd2, p->n_pollfd_alloc * sizeof(struct pollfd));
151 }
152
rtpoll_item_destroy(pa_rtpoll_item * i)153 static void rtpoll_item_destroy(pa_rtpoll_item *i) {
154 pa_rtpoll *p;
155
156 pa_assert(i);
157
158 p = i->rtpoll;
159
160 PA_LLIST_REMOVE(pa_rtpoll_item, p->items, i);
161
162 p->n_pollfd_used -= i->n_pollfd;
163
164 if (pa_flist_push(PA_STATIC_FLIST_GET(items), i) < 0)
165 pa_xfree(i);
166
167 p->rebuild_needed = true;
168 }
169
pa_rtpoll_free(pa_rtpoll * p)170 void pa_rtpoll_free(pa_rtpoll *p) {
171 pa_assert(p);
172
173 while (p->items)
174 rtpoll_item_destroy(p->items);
175
176 pa_xfree(p->pollfd);
177 pa_xfree(p->pollfd2);
178
179 pa_xfree(p);
180 }
181
reset_revents(pa_rtpoll_item * i)182 static void reset_revents(pa_rtpoll_item *i) {
183 struct pollfd *f;
184 unsigned n;
185
186 pa_assert(i);
187
188 if (!(f = pa_rtpoll_item_get_pollfd(i, &n)))
189 return;
190
191 for (; n > 0; n--)
192 f[n-1].revents = 0;
193 }
194
reset_all_revents(pa_rtpoll * p)195 static void reset_all_revents(pa_rtpoll *p) {
196 pa_rtpoll_item *i;
197
198 pa_assert(p);
199
200 for (i = p->items; i; i = i->next) {
201
202 if (i->dead)
203 continue;
204
205 reset_revents(i);
206 }
207 }
208
pa_rtpoll_run(pa_rtpoll * p)209 int pa_rtpoll_run(pa_rtpoll *p) {
210 pa_rtpoll_item *i;
211 int r = 0;
212 struct timeval timeout;
213
214 pa_assert(p);
215 pa_assert(!p->running);
216
217 #ifdef DEBUG_TIMING
218 pa_log("rtpoll_run");
219 #endif
220
221 p->running = true;
222 p->timer_elapsed = false;
223
224 /* First, let's do some work */
225 for (i = p->items; i && i->priority < PA_RTPOLL_NEVER; i = i->next) {
226 int k;
227
228 if (i->dead)
229 continue;
230
231 if (!i->work_cb)
232 continue;
233
234 if (p->quit) {
235 #ifdef DEBUG_TIMING
236 pa_log("rtpoll finish");
237 #endif
238 goto finish;
239 }
240
241 if ((k = i->work_cb(i)) != 0) {
242 if (k < 0) {
243 r = k;
244 AUDIO_ERR_LOG("Error %{public}d in i->work_cb, goto finish", r);
245 }
246 #ifdef DEBUG_TIMING
247 pa_log("rtpoll finish");
248 #endif
249 goto finish;
250 }
251 }
252
253 /* Now let's prepare for entering the sleep */
254 for (i = p->items; i && i->priority < PA_RTPOLL_NEVER; i = i->next) {
255 int k = 0;
256
257 if (i->dead)
258 continue;
259
260 if (!i->before_cb)
261 continue;
262
263 if (p->quit || (k = i->before_cb(i)) != 0) {
264
265 /* Hmm, this one doesn't let us enter the poll, so rewind everything */
266
267 for (i = i->prev; i; i = i->prev) {
268
269 if (i->dead)
270 continue;
271
272 if (!i->after_cb)
273 continue;
274
275 i->after_cb(i);
276 }
277
278 if (k < 0) {
279 AUDIO_ERR_LOG("Error %{public}d in i->before_cb, goto finish", r);
280 r = k;
281 }
282 #ifdef DEBUG_TIMING
283 pa_log("rtpoll finish");
284 #endif
285 goto finish;
286 }
287 }
288
289 if (p->rebuild_needed)
290 rtpoll_rebuild(p);
291
292 pa_zero(timeout);
293
294 /* Calculate timeout */
295 if (!p->quit && p->timer_enabled) {
296 struct timeval now;
297 pa_rtclock_get(&now);
298
299 if (pa_timeval_cmp(&p->next_elapse, &now) > 0)
300 pa_timeval_add(&timeout, pa_timeval_diff(&p->next_elapse, &now));
301 }
302
303 #ifdef DEBUG_TIMING
304 {
305 pa_usec_t now = pa_rtclock_now();
306 p->awake = now - p->timestamp;
307 p->timestamp = now;
308 if (!p->quit && p->timer_enabled)
309 pa_log("poll timeout: %d ms ",(int) ((timeout.tv_sec*1000) + (timeout.tv_usec / 1000)));
310 else if (p->quit)
311 pa_log("poll timeout is ZERO");
312 else
313 pa_log("poll timeout is FOREVER");
314 }
315 #endif
316
317 /* OK, now let's sleep */
318 #ifdef HAVE_PPOLL
319 {
320 struct timespec ts;
321 ts.tv_sec = timeout.tv_sec;
322 ts.tv_nsec = timeout.tv_usec * 1000;
323 r = ppoll(p->pollfd, p->n_pollfd_used, (p->quit || p->timer_enabled) ? &ts : NULL, NULL);
324 }
325 #else
326 r = pa_poll(p->pollfd, p->n_pollfd_used, (p->quit || p->timer_enabled) ? (int) ((timeout.tv_sec*1000) + (timeout.tv_usec / 1000)) : -1);
327 #endif
328
329 p->timer_elapsed = r == 0;
330
331 #ifdef DEBUG_TIMING
332 {
333 pa_usec_t now = pa_rtclock_now();
334 p->slept = now - p->timestamp;
335 p->timestamp = now;
336
337 pa_log("Process time %llu ms; sleep time %llu ms",
338 (unsigned long long) (p->awake / PA_USEC_PER_MSEC),
339 (unsigned long long) (p->slept / PA_USEC_PER_MSEC));
340 }
341 #endif
342
343 if (r < 0) {
344 if (errno == EAGAIN || errno == EINTR) {
345 r = 0;
346 } else {
347 AUDIO_ERR_LOG("Error %{public}d in ppoll, errno: %{public}s", r, pa_cstrerror(errno));
348 pa_log_error("poll(): %s", pa_cstrerror(errno));
349 }
350
351 reset_all_revents(p);
352 }
353
354 /* Let's tell everyone that we left the sleep */
355 for (i = p->items; i && i->priority < PA_RTPOLL_NEVER; i = i->next) {
356
357 if (i->dead)
358 continue;
359
360 if (!i->after_cb)
361 continue;
362
363 i->after_cb(i);
364 }
365
366 finish:
367
368 p->running = false;
369
370 if (p->scan_for_dead) {
371 pa_rtpoll_item *n;
372
373 p->scan_for_dead = false;
374
375 for (i = p->items; i; i = n) {
376 n = i->next;
377
378 if (i->dead)
379 rtpoll_item_destroy(i);
380 }
381 }
382
383 return r < 0 ? r : !p->quit;
384 }
385
pa_rtpoll_set_timer_absolute(pa_rtpoll * p,pa_usec_t usec)386 void pa_rtpoll_set_timer_absolute(pa_rtpoll *p, pa_usec_t usec) {
387 pa_assert(p);
388
389 pa_timeval_store(&p->next_elapse, usec);
390 p->timer_enabled = true;
391 }
392
pa_rtpoll_set_timer_relative(pa_rtpoll * p,pa_usec_t usec)393 void pa_rtpoll_set_timer_relative(pa_rtpoll *p, pa_usec_t usec) {
394 pa_assert(p);
395
396 /* Scheduling a timeout for more than an hour is very very suspicious */
397 pa_assert(usec <= PA_USEC_PER_SEC*60ULL*60ULL);
398
399 pa_rtclock_get(&p->next_elapse);
400 pa_timeval_add(&p->next_elapse, usec);
401 p->timer_enabled = true;
402 }
403
pa_rtpoll_set_timer_disabled(pa_rtpoll * p)404 void pa_rtpoll_set_timer_disabled(pa_rtpoll *p) {
405 pa_assert(p);
406
407 memset(&p->next_elapse, 0, sizeof(p->next_elapse));
408 p->timer_enabled = false;
409 }
410
pa_rtpoll_item_new(pa_rtpoll * p,pa_rtpoll_priority_t prio,unsigned n_fds)411 pa_rtpoll_item *pa_rtpoll_item_new(pa_rtpoll *p, pa_rtpoll_priority_t prio, unsigned n_fds) {
412 pa_rtpoll_item *i, *j, *l = NULL;
413
414 pa_assert(p);
415
416 if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items))))
417 i = pa_xnew(pa_rtpoll_item, 1);
418
419 i->rtpoll = p;
420 i->dead = false;
421 i->n_pollfd = n_fds;
422 i->pollfd = NULL;
423 i->priority = prio;
424
425 i->work_userdata = NULL;
426 i->before_userdata = NULL;
427 i->work_userdata = NULL;
428 i->before_cb = NULL;
429 i->after_cb = NULL;
430 i->work_cb = NULL;
431
432 for (j = p->items; j; j = j->next) {
433 if (prio <= j->priority)
434 break;
435
436 l = j;
437 }
438
439 PA_LLIST_INSERT_AFTER(pa_rtpoll_item, p->items, j ? j->prev : l, i);
440
441 if (n_fds > 0) {
442 p->rebuild_needed = 1;
443 p->n_pollfd_used += n_fds;
444 }
445
446 return i;
447 }
448
pa_rtpoll_item_free(pa_rtpoll_item * i)449 void pa_rtpoll_item_free(pa_rtpoll_item *i) {
450 pa_assert(i);
451
452 if (i->rtpoll->running) {
453 i->dead = true;
454 i->rtpoll->scan_for_dead = true;
455 return;
456 }
457
458 rtpoll_item_destroy(i);
459 }
460
pa_rtpoll_item_get_pollfd(pa_rtpoll_item * i,unsigned * n_fds)461 struct pollfd *pa_rtpoll_item_get_pollfd(pa_rtpoll_item *i, unsigned *n_fds) {
462 pa_assert(i);
463
464 if (i->n_pollfd > 0)
465 if (i->rtpoll->rebuild_needed)
466 rtpoll_rebuild(i->rtpoll);
467
468 if (n_fds)
469 *n_fds = i->n_pollfd;
470
471 return i->pollfd;
472 }
473
pa_rtpoll_item_set_before_callback(pa_rtpoll_item * i,int (* before_cb)(pa_rtpoll_item * i),void * userdata)474 void pa_rtpoll_item_set_before_callback(pa_rtpoll_item *i, int (*before_cb)(pa_rtpoll_item *i), void *userdata) {
475 pa_assert(i);
476 pa_assert(i->priority < PA_RTPOLL_NEVER);
477
478 i->before_cb = before_cb;
479 i->before_userdata = userdata;
480 }
481
pa_rtpoll_item_set_after_callback(pa_rtpoll_item * i,void (* after_cb)(pa_rtpoll_item * i),void * userdata)482 void pa_rtpoll_item_set_after_callback(pa_rtpoll_item *i, void (*after_cb)(pa_rtpoll_item *i), void *userdata) {
483 pa_assert(i);
484 pa_assert(i->priority < PA_RTPOLL_NEVER);
485
486 i->after_cb = after_cb;
487 i->after_userdata = userdata;
488 }
489
pa_rtpoll_item_set_work_callback(pa_rtpoll_item * i,int (* work_cb)(pa_rtpoll_item * i),void * userdata)490 void pa_rtpoll_item_set_work_callback(pa_rtpoll_item *i, int (*work_cb)(pa_rtpoll_item *i), void *userdata) {
491 pa_assert(i);
492 pa_assert(i->priority < PA_RTPOLL_NEVER);
493
494 i->work_cb = work_cb;
495 i->work_userdata = userdata;
496 }
497
pa_rtpoll_item_get_work_userdata(pa_rtpoll_item * i)498 void* pa_rtpoll_item_get_work_userdata(pa_rtpoll_item *i) {
499 pa_assert(i);
500
501 return i->work_userdata;
502 }
503
fdsem_before(pa_rtpoll_item * i)504 static int fdsem_before(pa_rtpoll_item *i) {
505
506 if (pa_fdsem_before_poll(i->before_userdata) < 0)
507 return 1; /* 1 means immediate restart of the loop */
508
509 return 0;
510 }
511
fdsem_after(pa_rtpoll_item * i)512 static void fdsem_after(pa_rtpoll_item *i) {
513 pa_assert(i);
514
515 pa_assert((i->pollfd[0].revents & ~POLLIN) == 0);
516 pa_fdsem_after_poll(i->after_userdata);
517 }
518
pa_rtpoll_item_new_fdsem(pa_rtpoll * p,pa_rtpoll_priority_t prio,pa_fdsem * f)519 pa_rtpoll_item *pa_rtpoll_item_new_fdsem(pa_rtpoll *p, pa_rtpoll_priority_t prio, pa_fdsem *f) {
520 pa_rtpoll_item *i;
521 struct pollfd *pollfd;
522
523 pa_assert(p);
524 pa_assert(f);
525
526 i = pa_rtpoll_item_new(p, prio, 1);
527
528 pollfd = pa_rtpoll_item_get_pollfd(i, NULL);
529
530 pollfd->fd = pa_fdsem_get(f);
531 pollfd->events = POLLIN;
532
533 pa_rtpoll_item_set_before_callback(i, fdsem_before, f);
534 pa_rtpoll_item_set_after_callback(i, fdsem_after, f);
535
536 return i;
537 }
538
asyncmsgq_read_before(pa_rtpoll_item * i)539 static int asyncmsgq_read_before(pa_rtpoll_item *i) {
540 pa_assert(i);
541
542 if (pa_asyncmsgq_read_before_poll(i->before_userdata) < 0)
543 return 1; /* 1 means immediate restart of the loop */
544
545 return 0;
546 }
547
asyncmsgq_read_after(pa_rtpoll_item * i)548 static void asyncmsgq_read_after(pa_rtpoll_item *i) {
549 pa_assert(i);
550
551 pa_assert((i->pollfd[0].revents & ~POLLIN) == 0);
552 pa_asyncmsgq_read_after_poll(i->after_userdata);
553 }
554
asyncmsgq_read_work(pa_rtpoll_item * i)555 static int asyncmsgq_read_work(pa_rtpoll_item *i) {
556 pa_msgobject *object;
557 int code;
558 void *data;
559 pa_memchunk chunk;
560 int64_t offset;
561
562 pa_assert(i);
563
564 if (pa_asyncmsgq_get(i->work_userdata, &object, &code, &data, &offset, &chunk, 0) == 0) {
565 int ret;
566
567 if (!object && code == PA_MESSAGE_SHUTDOWN) {
568 pa_asyncmsgq_done(i->work_userdata, 0);
569 /* Requests the loop to exit. Will cause the next iteration of
570 * pa_rtpoll_run() to return 0 */
571 i->rtpoll->quit = true;
572 return 1;
573 }
574
575 clock_t start = clock();
576 ret = pa_asyncmsgq_dispatch(object, code, data, offset, &chunk);
577 clock_t end = clock();
578 double deltatime = (double)(end - start) / CLOCKS_PER_SEC;
579 if (deltatime > 1.0) {
580 AUDIO_ERR_LOG("code %{public}d time out %{public}f s", code, deltatime);
581 }
582 pa_asyncmsgq_done(i->work_userdata, ret);
583 return 1;
584 }
585
586 return 0;
587 }
588
pa_rtpoll_item_new_asyncmsgq_read(pa_rtpoll * p,pa_rtpoll_priority_t prio,pa_asyncmsgq * q)589 pa_rtpoll_item *pa_rtpoll_item_new_asyncmsgq_read(pa_rtpoll *p, pa_rtpoll_priority_t prio, pa_asyncmsgq *q) {
590 pa_rtpoll_item *i;
591 struct pollfd *pollfd;
592
593 pa_assert(p);
594 pa_assert(q);
595
596 i = pa_rtpoll_item_new(p, prio, 1);
597
598 pollfd = pa_rtpoll_item_get_pollfd(i, NULL);
599 pollfd->fd = pa_asyncmsgq_read_fd(q);
600 pollfd->events = POLLIN;
601
602 pa_rtpoll_item_set_before_callback(i, asyncmsgq_read_before, q);
603 pa_rtpoll_item_set_after_callback(i, asyncmsgq_read_after, q);
604 pa_rtpoll_item_set_work_callback(i, asyncmsgq_read_work, q);
605
606 return i;
607 }
608
asyncmsgq_write_before(pa_rtpoll_item * i)609 static int asyncmsgq_write_before(pa_rtpoll_item *i) {
610 pa_assert(i);
611
612 pa_asyncmsgq_write_before_poll(i->before_userdata);
613 return 0;
614 }
615
asyncmsgq_write_after(pa_rtpoll_item * i)616 static void asyncmsgq_write_after(pa_rtpoll_item *i) {
617 pa_assert(i);
618
619 pa_assert((i->pollfd[0].revents & ~POLLIN) == 0);
620 pa_asyncmsgq_write_after_poll(i->after_userdata);
621 }
622
pa_rtpoll_item_new_asyncmsgq_write(pa_rtpoll * p,pa_rtpoll_priority_t prio,pa_asyncmsgq * q)623 pa_rtpoll_item *pa_rtpoll_item_new_asyncmsgq_write(pa_rtpoll *p, pa_rtpoll_priority_t prio, pa_asyncmsgq *q) {
624 pa_rtpoll_item *i;
625 struct pollfd *pollfd;
626
627 pa_assert(p);
628 pa_assert(q);
629
630 i = pa_rtpoll_item_new(p, prio, 1);
631
632 pollfd = pa_rtpoll_item_get_pollfd(i, NULL);
633 pollfd->fd = pa_asyncmsgq_write_fd(q);
634 pollfd->events = POLLIN;
635
636 pa_rtpoll_item_set_before_callback(i, asyncmsgq_write_before, q);
637 pa_rtpoll_item_set_after_callback(i, asyncmsgq_write_after, q);
638
639 return i;
640 }
641
pa_rtpoll_timer_elapsed(pa_rtpoll * p)642 bool pa_rtpoll_timer_elapsed(pa_rtpoll *p) {
643 pa_assert(p);
644
645 return p->timer_elapsed;
646 }
647